React useState cause double rendering
Put the console.log
in an useEffect
hook without dependencies and you'll see it isn't actually rendering twice.
import React, { useEffect, useState } from 'react';
const MyComponent = () => {
const [count, setCount] = useState(0);
useEffect(() => {
console.log(count);
});
return (
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
count: {count}
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
export default MyComponent;
Here's a good diagram of the component lifecycle, it lists the class-based lifecycle functions, but the render/commit phases are the same.
The import thing to note is that the component can be "rendered" without actually being committed (i.e. the conventional render you see to the screen). The console.log alone is part of that. The effects run after in the "commit" phase.
useEffect
... The function passed to useEffect will run after the render is committed to the screen. ...
By default, effects run after every completed render, ...
React Strict Mode
Detecting Unexpected Side-effects
Strict mode can’t automatically detect side effects for you, but it can help you spot them by making them a little more deterministic. This is done by intentionally double-invoking the following functions:
- Class component
constructor
,render
, andshouldComponentUpdate
methods- Class component static
getDerivedStateFromProps
method- Function component bodies
- State updater functions (the first argument to
setState
)- Functions passed to
useState
,useMemo
, oruseReducer
This only applies to development mode.
Some more info on double re-rending (as per a closed react issue).
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.
https://github.com/facebook/react/issues/15074
another related question is here.
useState() do double render