Do you want to request a feature or report a bug?
Bug (maybe)
What is the current behavior?
If wrapped in React.StrictMode and a function component contains a call to useState
, the function (render) is called twice - even if the state setter is never called.
If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem.
https://codesandbox.io/s/lyw9514j4q
(please see console)
What is the expected behavior?
I would expect it to only render once.
Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
16.8.3 in Chrome on macOS Mojave; requires hooks so not tested with previous versions.
This may be related to https://github.com/facebook/react/issues/12961 - but note that nowhere am I setting state (only initializing it).
If this is expected behavior please feel free to close. Thank you!
It's an intentional feature of the StrictMode. This only happens in development, and helps find accidental side effects put into the render phase. We only do this for components with Hooks because those are more likely to accidentally have side effects in the wrong place.
Sorry, I know this was closed, but you say
We only do this for components with Hooks...
but if your component uses a class -- even if it's stateless -- it also renders twice. Threw me for a loop today trying to figure out why my component wasn't working properly.
export default class App extends React.Component {
render() {
console.log('this logs twice with React.StrictMode');
return null;
}
}
Strict Mode always did this for classes. That’s the first thing it ever did. :-)
The question was about function components. So I explained that for function components, this was only on when they contained Hooks. In any case, we’ve changed that too already so it will fire for all function components soon.
If I'm understanding the documentation correctly, the purpose of this is to bring the developer's attention to lifestate function that are non-idempotent, because these might cause problems when concurrent mode is rolled out. So, I'm assuming just ignoring double renders that cause double sideeffects in StrictMode is not a good idea for future proofing.
~What then, is best practice for functions that get passed to useReducer
? Currently, I have a state that is an array, and the actions passed to the reducer are objects to append to the state. The reducer appends and returns the new state. The objects are singletons and may get sent to the dispatch function more than once, so just checking whether that object has been appended already doesn't work. What is the best practice design pattern for an idempotent reducer that appends to the state?~
Nevermind, I had a brain fart. It's a non-issue; both times the function is called in this double render, it is called with the same initial state, so appending again and returning will return the same result.
I know this one is closed, but I don't want to open a new ticket just for this.
What am I doing wrong here:
https://codesandbox.io/s/double-event-cb6hg
The first click will be triggered once, but subsequent clicks will add duplicate items.
My real app renders twice and dispatch is triggered twice on every click, this is just a contrived example.
Hey @nermand
(I think) the trouble you're seeing is because state.items.push
in your reducer modifies the array in place. This means you're trying to modify a piece of React state outside of the setter for that state.
The use of .push
can be replaced with a use of .concat
. Sandbox with the fix
Notice that reducer(state, event)
still gets called twice for each click (with the same objects for state
and event
in each call), but it is no longer an issue since state
is no longer changed between those two calls. As mentioned above, this is a deliberate behaviour of strict mode to help us notice issues like this.
Cheers @jaredkhan, that explains it.
We just need to keep treating every piece of state immutable and everything should be fine.
Thanks!
Hi, I understand the motivation for this. However, I really don't know how to approach a problem I have with debouncing an event handler. Here's a simplified version of my current code:
function ExampleComponent () {
const [debouncedHandlerFn] = useState(() => debounce(handlerFn, 1000))
return <div onSomeEvent={debouncedHandlerFn} />
}
What I'm trying to achieve here is to handle an event in a debounced manner. The debounce
function creates the debounced version of the handler.
I'm using lazy state initialization because it is the only way to put a function in the component state (it is also more efficient as it is not creating debounced versions of the function on every render).
What I expect is to have a unique debounced function instance per mounted component. This does work in production, but strict mode is rendering my component twice and executing the lazy-loading function twice. Actually I haven't checked if it still works fine (I guess it should, as it would retain the last instance, I'm gonna check now), but it doesn't seem like a clean way to go about this.
Any thoughts? Thanks :)
Nevermind, I got it. Figured out this is not a problem as long as the debounced function is being called from an event handler, as it will be called at later later after the second render is done, so no side-effects here.
🙆♂️ Dan's answer explained my confusion
But I still think it may be an added burden on the mind
In my project, I integrate SSR in which the server delivers data to client to be used in the first render.
To save memory, I want to clear the data after the first render (and also prevent the data from being re-used). Because StrictMode
makes the render happen twice, which always forces the data refetched (in the second render).
I have 2 questions. I really appreciate if anyone can help me figure it out
Yes. My render function has side effect. However, it only happens in the first render. If this is the case, will it break the concurrent mode in the future?
Is there any (best effort) way to satisfy these 3 purposes, priority from high to low:
StrictMode
Thank you very much.
Can you clean it in the effect?
Can you clean it in the effect?
Awesome. Thank you for opening my mind. I did not think about it.
~There is still one more point that I need to control the orders of data fetching, which I am solving now (and I think it can be handled).~ (I have changed to make all API endpoints with the same parameter return the same data. There is no more order check)
Thank you very much.
Edit: I have made it. No more warning, re-fetching.
Most helpful comment
It's an intentional feature of the StrictMode. This only happens in development, and helps find accidental side effects put into the render phase. We only do this for components with Hooks because those are more likely to accidentally have side effects in the wrong place.