Consider the following dummy code in React:
import { useEffect, useState } from "react";
const Welcome = () => {
console.log("[Welcome] rendered");
return <h1>Hello World</h1>;
};
const App = () => {
console.log("[App] rendered");
const [myState, setMyState] = useState(false);
useEffect(() => {
console.log("[App - useEffect] Callback");
setMyState(true);
});
return <Welcome />;
};
export default App;
The output on console when I run this application is:
[App] rendered
[Welcome] rendered
[App - useEffect] Callback
[App] rendered
[Welcome] rendered
[App - useEffect] Callback
[App] rendered
First Doubt:
Why is the last message which prints [App] rendered printed for the third time on console when there is no state change (myState is true and set to true again)? If at all the App component is rendered again, why [Welcome] rendered is not printed after it?
Problem Explanation:
When I run the application, the App component renders for the first time giving the message [App] rendered on console. Since the App component has Welcome as its child component, the message [Welcome] rendered is printed on console and the child component Welcome is mounted on DOM thereby mounting the App component too. Once the App component is mounted on DOM, the callback function inside the useEffect hook gets executed and it prints [App - useEffect] Callback on console. The next statement inside this callback function sets the myState state variable to true (which was previously false). Because the state of App component has changed, it gets re-rendered. This prints another [App] rendered statement on console. To render App, Welcome component needs to be rendered which prints [Welcome] rendered on console. Once the App component is rendered (or evaluated) completely, the control goes to the useEffect hook and the statement [useEffect] Callback is again printed on console. This time again, I set the state variable myState to true (which was previously also true) thereby making no change in state from the previous render and hence there is no re-rendering of the App component. Hence, I should not see the third [App] rendered message printed on console.
Second Doubt:
For my second doubt, consider the slightly changed code given below (set myState to false in contrast to setting it to true earlier):
import { useEffect, useState } from "react";
const Welcome = () => {
console.log("[Welcome] rendered");
return <h1>Hello World</h1>;
};
const App = () => {
console.log("[App] rendered");
const [myState, setMyState] = useState(false);
useEffect(() => {
console.log("[App - useEffect] Callback");
setMyState(false);
});
return <Welcome />;
};
export default App;
The output on console when I run this slightly modified application is:
[App] rendered
[Welcome] rendered
[App - useEffect] Callback
If the [App] rendered was printed for the third time in the previous code, then why is the message [App] rendered not getting logged for the second time here? Why there exists an inconsistency between the results of the two code snippets?
P.S.
The dummy code is kept trivial so that I can focus more on the concept than the code and I have deliberately not used any dependency array in useEffect.