I was doing some tests with the following dummy component, where upon the execution (in the console) I am getting the following result:
Rendering: 0
Triggered: 0
Rendering: 4
Triggered: 4
Rendering: 4
I struggle to understand why.
First rendering:
index to 0.undefined is not 0index to 4Second render:
index is 4Third render:
What I would expect is:
Rendering: 0
Triggered: 0
Rendering: 4
Am I skipping something very obvious? Could you please help me understand how this works under the hood?
const Example = React.memo(() => {
const [index, setIndex] = React.useState(0)
console.log('Rendering: ', index)
React.useEffect(() => {
console.log('Triggered: ', index)
setIndex(4)
}, [index])
return <h1>{index}</h1>
})
ReactDOM.render(<Example />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
The number of rerenders are actually correct. Let's analyze what happens:
useEffect is run automatically)useEffectindex to 4index from 0 to 44 to 4 (even the value is the same, it will trigger component rerender because React does not know if you set same state, and it needs to run again). In this rerender useEffect is not run because index is 4 again.If anything changes in a component at any point like useState useContext, customHook, that component will need to rerender.
This also happens if the parent component rerenders, child component will rerender even if your component did not have any changes.
To prevent parent unnecessary rerendering of child components from happening you can use React.memo, this will rerender your component if props change, but wont prevent your component from rerendering if state or any of the above hooks change in there.
If this seems redundant, it sounds like it, but it is necessary so that react is sure it has the latest state. Running JS like this is faster than having some state memory that checks changes and also it is more transparent for the developer (and just how the VDOM is created)
Expected output can't be achieved.
useEffect renders on when component mount and on every re-render when state changes(index).
const Example = () => {
const [index, setIndex] = React.useState(0)
console.log('Rendering: ', index)
React.useEffect(() => {
console.log('Triggered: ', index)
setIndex(4)
}, [index])
return <h1>{index}</h1>
}
Output:
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