I test some code and make me confused
There are two reproduction,
- use setState function set State to same previous state value
const [state, setState] = useState(1)
setState(() => 1)
- use setState function set State to same value(always same ex: 1, true, something else), but different initial state
const [state, setState] = useState(1)
setState(() => 2)
This is reproduction sample 1
always set state to same value
open codesandbox console first and clear it first.
what happened
click, state is already 1, setState function set state to 1,
component function does not re-run
// console show
test
test
test
This is reproduction sample 2
I always set state to 2.
First click, state is change from 1 to 2, so component function re-run
// console
test
app
Second click, state already is 2, but why component function still re-run
// console
test
app <-------------- here component function re-run
Third click, state already is 2 , component function does not re-run
// console
test
The Problem is Here
In Sample 2, second click button, state is same as previous, but is still re-run component.
And we go back to see Sample 1 and third click in Sample 2, these two state change step is same as Sample 2 second click, they are all same set same state compare to previous state, but how they output is different
As I know, state change will cause component function re-run.
What I expect is Sample 2 second click, component function is not re-run
CodePudding user response:
Let's focus only on Simple 2 as Simple 1 flow is what a developer would expect.
Simple 2 logs are as follow:
1. app // first render
2. test // button click, log from the callback
3. app // state change from '1' to '2', second render
4. test // second button click
5. app // no state change, why the log?
6. test // 3rd button click
7. test // 4th button click etc.
So the main question is why there is a 5th log of 'app'. The reasoning behind it hides somewhere in React docs under Bailing out of a state update:
Note that React may still need to render that specific component again before bailing out. That shouldn’t be a concern because React won’t unnecessarily go “deeper” into the tree.
In simple words, its just an edge case where React needs another render cycle but it doesn't goes into the Nodes tree (i.e it doesn't run the return statement, in your example it's a React.Fragment <></>
)
A more concrete example, notice the addition log of "A":
const App = () => {
const [state, setState] = React.useState(0);
useEffect(() => {
console.log("B");
});
console.log("A");
return (
<>
<h1>{state}</h1>
<button onClick={() => setState(42)}>Click</button>
</>
);
};
ReactDOM.render(<App />, document.getElementById("root"));