This question already has answers here:
React Hooks: useEffect() is called twice even if an empty array is used as an argument
(20 answers)
Closed 25 days ago.
Originally I was going to title this, Is componentDidMount() Better than useEffect with dependency array []?
I have two different react projects.
Project A was made using version "react": "^16.14.0",
Project B was made with version "react": "^18.2.0",
in Project A I used componentDidMount mostly for performing state change/api pulls/ etc and console.log on top to make sure the componentDidMount life-cycle ran only onces.
in Project B I am using useEffect to perform similar actions, and again I have a console.log right on top to make sure the useEffect (life cycle) runs only one... it does not, it runs TWICE. And I am very very confused Why on Earth would it be run twice? Has anyone else ran into such an issue? The code is a very simple console.log
React.useEffect(()=>{
console.log("app()")
},[])
I Expect it to run ONLY ONCE, but it runs twice.
Additionally, I even have a useMemo with the dependency which console.log twice instead of once. I am certain my implementation is correct. The code works, the UI displays data as expected.
As a matter of fact EVERY Console.log is running twice in Project B . Has anyone else run into an issue where they get Extra console.log, and how did you resolve it?
Thx
This is because of React.StrictMode. In development mode only, it will mount every component twice to help catch accidental impurities in your code.
Related
When I learn React, everyone tells me setState is async because if I console.log(state) right after setState, it will print the old value.
However, when I check the source code, useState doesn't return any promise nor use async/await.
Meaning setState must be sync. But if it's sync then why React doesn't re-render the component right away when I call setState? As you can see in the code snippet below, 0 gets printed first, then render1 is printed later.
If this is because of batching then how does batching work? How is it possible to "wait" until specific time to trigger the re-render of App component. And even more important, how does React know that it needs to call App in this case and not other functions?
export default function App(){
const [count, setCount] = useState(0);
console.log("render", count);
return <button onClick={() => {
setCount(count+1); // why doesn't App get called/re-rendered right away here
console.log(count); // this prints the old value first then re-render happens later
}}>
</button>
}
First, I would caution you that the reason why console.log(count) logs out the old value has nothing to do with sync vs async. The reason why you log out the old value is that count is a local const which will never change. It started its existence as the old value, and it will always be the old value no matter how much time passes, and no matter the order of operations.
Calling setCount does not change the value in count, it just asks react to rerender the component. When that new render happens, a new set of local variables will be created, with the new values. But your console.log from the previous render can't interact with values in the next render.
That said, it is true that rendering in react is (usually) delayed briefly to batch up multiple changes. The exact way they do this i'm not sure, because there's several possibilities. I've previously looked through their code, but enough has changed in the last few years that i doubt what i found will still be useful. In any event, ways that they could batch the rerender include:
setTimeout. The first time you set a state, they could set a timeout to go off soon. If another set state happens, they take note of the state, but don't bother setting an additional timeout. A little later, the timeout will go off and the rendering happens.
A microtask. The easiest way to do this is Promise.resolve().then(/* insert code here */). Once the current call stack finishes executing, microtasks will run. This approach has the benefit that it can happen sooner than a setTimeout, since timeouts have a minimum duration
If execution began inside react, they could just wait until your code returns, then do the render. This used to be the main way react batched changes. Eg, they had a piece of code responsible for calling your useEffects. During that, it would take note of state changes, but not rerender yet. Eventually you return, and since returning puts code execution back in react's hands, it then checks which states have changed and rerenders if needed.
how does React know that it needs to call App in this case and not other functions?
It knows that because the state that you changed is a state of App. React knows the tree structure of your components, so it knows it only needs to render the component where you set state, plus its children.
In my React Native app, I have several state variables that get initialized to zero in the constructor, and then updated by the user. The problem is that when I'm running the app on an emulator, whenever I save my code, the emulator hot reloads, and the constructor gets run, thereby resetting all these state variables to zero. Is there a standard way to handle this? Or should I just actually reload every time this happens, and assume this won't be a problem when I'm running the app in real life?
Thats not something you can handle it. Bundler does everything. Sometimes it resets states sometimes does not. Always remaps all bundles and patch them through the DOM and it depends on your DOM tree.
I currently use the useEffect hook to run some function or update a variable as an effect of another value/variable being changed
example:
useEffect(() => {
setValues(types[formStep]]);
}, [formStep]);
I am using the above code to update a variable after another variable has changed, however i keep getting the warning that
React Hook useEffect has a missing dependency 'types
and obviosuly when i include 'types' as a dependency, the application falls into a loop and i get the following error
Maximum update depth exceeded.
What is the best way to achieve the variable update but avoid the error? not just for this example for for all cases where you need to update a variable depending on another variable changing before it.
Some solutions found here: https://www.benmvp.com/blog/object-array-dependencies-react-useEffect-hook/.
Another option could be to stringify the dependency so that it is not treated as a different object everytime.
useEffect(() => {}, [JSON.stringify(data)])
What is the best way to achieve the variable update but avoid the error?
It depends on a lot of factors: sometimes using a ref (if you don't want to trigger an update), sometimes you are just deriving state and there is not need for use-effect (I think that this could be your case), other times you need to trigger an update only when certain value(s) has changed... Sometimes the next value depends on the previous one so you should use the function overload of setState and avoid passing the previous value as a dependency... There is not a generic answer to this problem.
It's difficult to know what's happening in your case without more context. However, I think that I have an idea of what could be happening... This is just a shot in the dark.
Is types an Object that you are defining inside the function of the component? Can you move that definition outside of the function of the component? Because if you can do that, then there is no need to pass it as a dependency.
Also, do you really need to use useState and useEffect for setting values? Do you really need to trigger another update? can't you just do this?
const values = types[formStep];
I am trying to debug performance issues in a React app,there is any method or 'devtools' or any means to check the performance of my component to prevent the failure of wasted renders
You can use https://github.com/welldone-software/why-did-you-render , its a more maintained up to date version of why-did-you-update (https://github.com/maicki/why-did-you-update) , it will print warnings in your console whenever an unnecessary re-render happens in one of your components.
Common optimisations you can do to prevent unnecessary renders include using PureComponent instead of Component, or use React.memo for function components, as well as hoist styles/object literals and function declarations outside of your render functions as they return a new reference every time.
You can check https://reactjs.org/docs/perf.html
Specifically take a look on printwasted https://reactjs.org/docs/perf.html#printwasted
“Wasted” time is spent on components that didn’t actually render
anything, e.g. the render stayed the same, so the DOM wasn’t touched
I'd like to run a function upon receiving props initially and upon any subsequent props changes. Consequently, I was planning on checking props and running this function in both componentDidMount and componentWillReceiveProps. However, this seems redundant. I've seen people also check props and run functions inside render(), but I was under the impression this was frowned upon.
What should be my solution here?
There is no substitute to catch both componentDidMount and componentWillReceiveProps in a single callback. The best way to do this is to define a function and call it from both of these callbacks.
I was planning on checking props and running this function
Is a very vague description of what you're trying to do. Just checking the props alone doesn't seem to be problematic if done inside the render function. But it would become a problem if this part is causing side effects which (can) in turn trigger a component re-render. If this is the case, I'd say "frowned upon" is putting it lightly. The problem with this is that your render function is adding side effects which are in turn triggering more re-renders and on it goes. It will instantly kill the performance of your app and could even make the whole thing grind to a halt.
Your question is tagged with both React and Redux. Are you using a mapStateToProps function that you use with connect?
If so, a possible answer could be to dispatch this action (or run this function) in the mapStateToProps function, since this will be run both initially, and then every time you update the redux state. You'd have to make sure the action/function doesn't cause yet another state change though, so that you end up in a loop.
Edit: #DuncanThacker pointed out this might not be a good idea, because mapStateToProps may fire very often, resulting in performance issues. Good point.