Search code examples
reactjsreact-hooksuse-effectuse-state

React useEffect hook has a missing dependency warning


Quick question, how do I fix the warning that I get when I try to use useEffect in my app. Here is my code:

 const userUrl = `${process.env.REACT_APP_API_URL}/${id}`;


const [newUser, setNewUser] = useState({
    name: "",
    email: "",
    status: "",
    gender: "",
  });

  useEffect(() => {
    if (id) {
      const getUser = async () => {
        try {
          const response = await axios.get(userUrl);
          const apiData = response.data.data;
          setNewUser({
            ...newUser,
            name: apiData.name,
            email: apiData.email,
            status: apiData.status,
            gender: apiData.gender,
          });
        } catch (err) {
          console.error(err);
        }
      };
      getUser();
    } else {
      setNewUser({
        ...newUser,
        status: "active",
        gender: "male",
      });
    }
  }, [userUrl, id]);

This is the full warning message: React Hook useEffect has a missing dependency: 'newUser'. Either include it or remove the dependency array. You can also do a functional update 'setNewUser(n => ...)' if you only need 'newUser' in the 'setNewUser' call

I tried adding the newUser inside the second parameter of the useEffect hook, but then I get the maximum depth error, so if anyone know how to fix this, I would gladly appreciate that.


Solution

  • Issue

    The issue here is that you are referencing the newUser state within the useEffect callback, thus making it a dependency. But you can't unconditionally update any value that is a dependency as this leads to the render looping you see when you added newUser state as a dependency.

    Solution

    You should use a functional state update on the state updater so you can remove the outer newUser dependency. The functional update enqueues a state update and passes the previous state value to the callback that can be used to compute the next state value.

    useEffect(() => {
      if (id) {
        const getUser = async () => {
          try {
            const response = await axios.get(userUrl);
            const { email, gender, name, status } = response.data.data;
            setNewUser(newUser => ({ // <-- previous state
              ...newUser,            // <-- shallow merge
              name,
              email,
              status,
              gender,
            }));
          } catch (err) {
            console.error(err);
          }
        };
        getUser();
      } else {
        setNewUser(newUser => ({     // <-- previous state
          ...newUser,                // <-- shallow merge
          status: "active",
          gender: "male",
        }));
      }
    }, [userUrl, id]);