Consider the following Component
const Component = () =>{
const [state, setState] = useState(null)
const onClick = () => setState('foo')
console.log(state)
return <button onClick={onClick}> Change </button>
}
console
just prints null
console
prints foo
console
print foo
console
doesn't print anythingI understand that console
doesn't print anything cause I'm calling setState
passing the same value as the current state and React is bailing out the state update. My question is about the following assertion
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. If you’re doing expensive calculations while rendering, you can optimize them with useMemo.
Why is this extra render necessary? I mean, Isn't Object.is
returning false
since the second click?
React will then look at the virtual DOM, it also has a copy of the old virtual DOM, that is why we shouldn't update the state directly, so we can have two different object references in memory, we have the old virtual DOM as well as the new virtual DOM.
As we already saw before, React re-renders a component when you call the setState function to change the state (or the provided function from the useState hook in function components). As a result, the child components only update when the parent component's state changes with one of those functions.
This is a function available to all React components that use state, and allows us to let React know that the component state has changed. This way the component knows it should re-render, because its state has changed and its UI will most likely also change.
You can see in the console tab, that the render lifecycle got triggered more than once on both the app and greeting component. This is because the React app component got re-rendered after the state values were modified, and it also re-rendered its child components.
Internally useState is a useReducer, with a basicReducer, The hooks uses a queue of changes in order to update the states.
AFAIK after looking the code it is a condition where the memoizedState is not fully processed in the queue, because is no using the fine control of the hook useMemo
I got a satisfatory answer from a deleted answer in this same question. d.c pointed that Dan Abrahmov gave an answer in this old github issue. Quoting Dan:
I think at the time we decided that we don't actually know if it's safe to bail out in all cases until we try render again. The "bailout" here means that it doesn't go ahead to render children. But re-running the same function might be necessary (for example, if a reducer is inline and we don't know if we bail out until we re-run the reducer on next render). So for consistency we always re-run it on updates during the render phase.
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