difference between -
this.setState({value: 'xyz', name: 'john', color: 'orange'})
vs
setValue('xyz');
setName('john');
setColor('orange');
do hooks work/uses synchronously? And when it starts actual rendering after the first setValue or on setColor state?
I also wanted to how it works under the hood?
setState is merging the previous state with the new one, it means that you dont have to pass the full state object every time you want to change some part of the state.
React will update given properties and won't touch the rest.
The useState's updater rewrites a previous state with a new one and it does not perform any merging.
Its just replacement instead of merging.
1. Behind the scene, hooks are stored like linklist
https://medium.com/flatiron-labs/breaking-the-rules-of-react-hooks-9e892636641e
https://github.com/facebook/react/blob/9f395904c6033598ba8bf47f5497fd6e5077c16d/packages/react-reconciler/src/ReactFiberHooks.js
Hooks are stored as a linked list on the fiber's memoizedState field. The current hook list is the list that belongs to the current fiber. The work-in-progress hook list is a new list that will be added to the work-in-progress fiber.
2. Hook is executed one by one, and every render is based on a whole new hook linked list
So, in case of multiple useState hooks, is different from the class component which state is updated or executed together in just one state object, everytime changing state would trigger rerender. Hook is executed seperately, and changed of one hook wouldn't cause component render immediately, it depends on the react fibre's core algorithm.
And by the article above, every render would create a new hook linked list, therefore hooks must be called in the same order every render.
By the document of React: https://reactjs.org/docs/hooks-rules.html#explanation
... is that React relies on the order in which Hooks are called.
If the order is different between first render and second render, it would cause bug.
And about your example, let's say that you have code like this:
const [value, setValue] = useState('xyz');
const [name, setName] = useState('John');
const [color,setColor] = useState('Orange')
Then react would build a hook linklist and the head node is setValue hook, next node would be setName, and next node would be setColor. And when
setValue('abc') executed, react would pull out the head node from old linked list, change the value of it, and refer the next node of it to make a new linkedlist. And if this line setName('Bill') is executed next, then react would do the thing above again.
But when component rerender be triggered? Actually, I am not sure, but we could use an example as below.
case test1
Inside function handleClick, when setCount(count + 1) is executed, react wouldn't make component render immediately, and when the next line setValue(value + count) is executed, the count still refers to old state. Clicked 5 times, this component render 6 times totally.
case test2
In this case, the second set state setValue(value + count) is triggered 3 seconds later after setCount(count + 1) is executed. And result is, when setCount(count + 1) is executed, component render immediately, 3 seconds later after setValue(value + count) is executed, component render again, but state count still refers to old state,. Clicked 5 times, this component render 11 times totally.
So, it depends on the react fibre's core algorithm.
You could try the code below:
case test1
const {useState} = React;
const App=()=> {
console.log("render App")
const [count, setCount] = useState(0);
const [value, setValue] = useState('xyz');
//console.log(value)
if(count> 5) //Before count >5 , the order of hooks is : 1.setCount, 2.setValue, 3.setColor , when count is above 5, then change the order of hooks as : 1.setCount, 2.setValue, 3.setName, 4.setColor
{
const [name, setName] = useState('John');
}
const [color,setColor] = useState('Orange')
function handleClick(e) {
setCount(count + 1)
setValue(value + count)
//setTimeout(()=>setValue(value + count),3000)
}
return (
<div>
<p>You clicked {count} times, when above 5 times, this function would crash, because order of hooks is changed</p>
<p>And the 'value' is : {value}, and you might find value didn't plus the new state of count, but old state of count</p>
<button onClick={handleClick}>
Click me
</button>
</div>
);
}
ReactDOM.render(
<App/>,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
case test2
const {useState} = React;
const App=()=> {
console.log("render App")
const [count, setCount] = useState(0);
const [value, setValue] = useState('xyz');
//console.log(value)
if(count> 5) //Before count >5 , the order of hooks is : 1.setCount, 2.setValue, 3.setColor , when count is above 5, then change the order of hooks as : 1.setCount, 2.setValue, 3.setName, 4.setColor
{
const [name, setName] = useState('John');
}
const [color,setColor] = useState('Orange')
function handleClick(e) {
setCount(count + 1)
//setValue(value + count)
setTimeout(()=>setValue(value + count),3000)
}
return (
<div>
<p>You clicked {count} times, when above 5 times, this function would crash, because order of hooks is changed</p>
<p>And the 'value' is : {value}, and you might find value didn't plus the new state of count, but old state of count</p>
<button onClick={handleClick}>
Click me
</button>
</div>
);
}
ReactDOM.render(
<App/>,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With