In your code, there is no third render. it's component invoking, not rendering.
For example:
import { useEffect, useState } from "react";
export default function App() {
const [buttonClicked, setButtonClicked] = useState(false);
console.log("invoked");
useEffect(() => {
console.log("render");
});
return (
<div className="App">
<button onClick={() => setButtonClicked(true)}>true</button>
<button onClick={() => setButtonClicked(false)}>false</button>
{buttonClicked && <div>Button was clicked</div>}
</div>
);
}
To test this code, please go to codesandbox.
This code logs in console like this:
invoked // first mount
render // first mount
invoked // first click true button (if you click false button, there is no effect)
render // first click true button
invoked // second click true button, after then if you click true button, there is no logging.
invoked // first click false button
render // first click false button
invoked // second click false button, after then if you click false button, there is no logging.
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 the console.log
statement inside the useEffect
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:
If you update a State Hook to the same value as the current state,
React will bail out without rendering the children or firing effects.
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.
UPDATED ANSWER
In my example, if you click false
button the first time, you can't see any more logs. It's because React already bailed out after the first mount.
You can see this:
invoked // first mount
render // first mount