You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I ran in to this interesting dynamic that I cannot explain today.
The code sets some initial state, which is a random number, and logs this initial value.
It converts the number to a string using useMemo, which logs the number it is converting, and is dependant on that number (not the string). And
when the component is mounted, I force a re-render by changing a boolean state once.
The result is that the initial value of the number is changed (and the log is output) so you see the number being set twice to two different values - this only happens in StrictMode. It is surprising. Is it expected?
You also see the useMemo being computed ONCE - only the first time. So seemingly it does not recompute a new string value.
BUT, the output in the HTML is the correct and shows the stringified value of the second number.
So what is happening here? Is the console log swallowed? Is useMemo behaving correctly, and more importantly, is the initialValue of useState supposed to change like that?
Steps To Reproduce
exportdefaultfunctionApp(){const[rand]=useState(Math.random());const[,setState]=useState(false);console.log(`Number: ${rand}`);useEffect(()=>{setState(true);},[]);consttext=useMemo(()=>{console.log(`Computing text from ${rand}`);returnrand.toString();},[rand]);return(<divclassName="App"><h1>Rand: {rand}</h1><h1>Text: {text}</h1></div>);}
To avoid confusion, React temporarily suppresses console logs during the second run (see #18547). This has been somewhat controversial as it can cause confusion. The pros and cons have been discussed in length on other issues though so I'm going to defer to those here and not repeat the arguments. #15315
How did it even become noticeable in this case? Because you're using a random value. React components are expected to be idempotent: Rendering a component multiple times with the same input should always yield the same output. (This includes initial state values.)
The reason it's confusing in this case is that the state is being initialized to a random value rather than a deterministic value. If you have to use something like Math.random(), our recommendation would be to move the generation of the random value to the (e.g. event or whatever that scheduled the update) and pass it to your component as a prop. This way it only runs once and your component can safely be paused or re-rendered later without side effects.
React version: 17.0.2
I ran in to this interesting dynamic that I cannot explain today.
useMemo
, which logs the number it is converting, and is dependant on that number (not the string). AndThe result is that the initial value of the number is changed (and the log is output) so you see the number being set twice to two different values - this only happens in
StrictMode
. It is surprising. Is it expected?You also see the
useMemo
being computed ONCE - only the first time. So seemingly it does not recompute a new string value.BUT, the output in the HTML is the correct and shows the stringified value of the second number.
So what is happening here? Is the console log swallowed? Is
useMemo
behaving correctly, and more importantly, is theinitialValue
ofuseState
supposed to change like that?Steps To Reproduce
And wrap your app in
StrictMode
Link to code example:
https://codesandbox.io/s/strict-mode-random-bug-ml3gv
The current behavior
initial state computed twice.
usememo seemingly not run twice
The expected behavior
Initial state computed once?
Or usememo runs twice?
The text was updated successfully, but these errors were encountered: