'React Hooks: Why I have this output?

I'm studying React hooks but i am not able to understand why I got this output in the console. Someone with great heart could explain in detail the "running execution" oh these hooks?

import { useState, useEffect } from "react";
function Homepage() {
  const [state, setState] = useState();
  useEffect(() => {
    console.log("useEffect");
    console.log("useEffect not executed");
    setState("hello")
  }, []);
  if (!state) {
    console.log("state not defined");
    return <div>State undefined</div>;
  }
  return <div>ciao</div>;
}
export default Homepage;

console output: state not defined state not defined useEffect useEffect not executed useEffect useEffect not executed



Solution 1:[1]

Basically it's a combination of React.StrictMode double invoking the function body twice as a way to help you detect unexpected side-effects

Strict mode can’t automatically detect side effects for you, but it can help you spot them by making them a little more deterministic. This is done by intentionally double-invoking the following functions:

  • Class component constructor, render, and shouldComponentUpdate methods
  • Class component static getDerivedStateFromProps method
  • Function component bodies <-- this
  • State updater functions (the first argument to setState)
  • Functions passed to useState, useMemo, or useReducer

remounting the component to ensure reusable state

To help surface these issues, React 18 introduces a new development-only check to Strict Mode. This new check will automatically unmount and remount every component, whenever a component mounts for the first time, restoring the previous state on the second mount.

and the useEffect hook being called at the end of the render cycle.

function Homepage() {
  const [state, setState] = useState();

  useEffect(() => {
    console.log("useEffect"); // logs second as expected side-effect
    console.log("useEffect not executed");
    setState("hello");
  }, []);

  if (!state) {
    console.log("state not defined"); // logs first as unintentional side-effect
    return <div>State undefined</div>;
  }

  return <div>ciao</div>;
}

...

import { StrictMode } from "react";
import { createRoot } from "react-dom/client";

import Homepage from "./Homepage";

const rootElement = document.getElementById("root");
const root = createRoot(rootElement);

root.render(
  <StrictMode>
    <Homepage />
  </StrictMode>
);

Explaining the logs

console output:

state not defined      // <-- initial render
state not defined      // <-- double invocation of function body
useEffect              // <-- effect at end of initial render
useEffect not executed // <-- effect at end of initial render

...unmount/mount

useEffect              // <-- effect at end of render
useEffect not executed // <-- effect at end of render

Solution 2:[2]

useEffect runs when the page renders and the other functions execute before useEffect so your code runs the if (!state) first then useEffect runs and state sets to "hello"; here is a link to fully understand useEffect hook: useEffect; Good luck;

Solution 3:[3]

your if statement is running before the useEffect even tho is after it, you need to put both divs inside the return and remove the if

   return (
     {!state ? <div>State undefined</div> : <div>ciao</div>}
   )

Solution 4:[4]

  1. state not defined first render of your component Homepage
  2. state not defined 2nd render
  3. useEffect useEffect not executed your component is mounted, so the useEffect hook is triggered.
  4. useEffect useEffect not executed here your component rerender with the state hello the useEffect hook is triggered again

In practice, useEffect hook runs at minimum following your dependency array. Here your set [] so the useEffect hook runs when the component mounts, but sometimes it can still be triggered.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Ali Navidi
Solution 3 c0dm1tu
Solution 4 Frédéric Lang