import { useState } from "react";
export default function App() {
const [buttonClicked, setButtonClicked] = useState(false);
console.log('Render');
return (
<div className="App">
<button onClick={() => setButtonClicked(true)}>Click me</button>
{buttonClicked && <div>Button was clicked</div>}
</div>
);
}
This component is not running in the StrictMode
. It renders first, so we see one render in the console. When we click the button it rerenders because of the state update. We can see ‘Render’ in the console once again. But, to my surprise, when we click the button once again it also rerenders the component, and we see ‘Render’ in the console for the 3rd time.
I thought the state update was checking if the value has changed, so it wouldn’t render for the 3rd time.
What’s even more weird to me, is when we click the button for the 3rd time, it doesn’t rerender the component.
Why is this happening?
Codesandbox:
https://codesandbox.io/s/proud-star-rg49x9?file=/src/App.js:0-336
2
Answers
In your code, there is no third render. it’s component invoking, not rendering.
For example:
To test this code, please go to codesandbox.
This code logs in console like this:
The
console.log
statement outside the return is not related to the rendering process. It is just a normal JavaScript statement that runs every time the function is invoked. The component function can be invoked for various reasons, such as props changes, context changes, or parent re-renders.React may invoke the component function to check for changes in the output, but it will not re-render the component or its children unless there is a difference in the output. So, the
console.log
statement outside the return will run every time the component function is invoked, but theconsole.log
statement inside theuseEffect
hook will only run after the initial render and after every re-render.React will bail out of re-rendering if the state value is the same as before.
According to React documentation:
This means that after clicking the same button twice, React will not re-render the component or its children because there is no change in the output. React will also not invoke the component function again unless there is a reason to check for changes in the output, such as props changes, context changes, or parent re-renders. This is how React optimizes the performance of your application by avoiding unnecessary work.
You can use memo to skip rendering a component if its props have not changed: