Huan Li
Huan Li

Reputation: 31

useEffect has a missing dependency

I want to implement componentDidMount in hooks that I want to do something for the first rendering ONLY, so in the useEffect, I set the dependency array as empty, but eslint has the warning that dependency is missing. how to solve it?

import React, { useEffect, useState } from "react";
import ReactDOM from "react-dom";

const Child = ({ age }) => {
  useEffect(() => {
    console.log("simulate componentDidMount, age:", age);
  }, []);

  useEffect(() => {
    console.log('simulate componentDidUpdate, age:', age)
  }, [age])

  return <div>age: {age}</div>;
};

const App = () => {
  const [age, setAge] = useState(0);
  const handleOnClick = e => {
    e.preventDefault();
    setAge(a => a + 1);
  };
  return (
    <>
      <Child age={age} />
      <button onClick={handleOnClick}>INCREASE AGE</button>
    </>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Upvotes: 2

Views: 197

Answers (4)

Asaf Aviv
Asaf Aviv

Reputation: 11760

You can store the first render in a ref and do what you need to do when isFirstRender.current is true, this way you don't need to add anything but age to your effect and can combine cDM and cDU together, storing the lifecycle in state doesn't make sense to me.

const Child = ({ age }) => {
  const isFirstRender = useRef(true);

  useEffect(() => {
    if (isFirstRender.current) {
      isFirstRender.current = false;
      console.log("simulate componentDidMount, age:", age);
      return
    }
    console.log('simulate componentDidUpdate, age:', age);
  }, [age]);

  return <div>age: {age}</div>;
};

You can also extract it into a custom hook if you want to reuse it

const useIsFirstRender = () => {
  const isFirstRender = useRef(true);

  useEffect(() => {
    isFirstRender.current = false;
  }, []);

  return isFirstRender.current;
};

const Child = ({ age }) => {
  const isFirstRender = useIsFirstRender();

  useEffect(() => {
    if (isFirstRender) {
      console.log("simulate componentDidMount, age:", age);
      return;
    }
    console.log('simulate componentDidUpdate, age:', age)
  }, [age, isFirstRender]);

  return <div>age: {age}</div>;
};

Upvotes: 2

Leo Farmer
Leo Farmer

Reputation: 7890

You could do something like this if you don't want to disable eslint:

const [component_mounted, set_component_mounted] = useState(false)

useEffect(() => {
    if(!component_mounted) {
      // Use age here
      set_component_mounted(true)
    }
  }, [age, component_mounted, set_component_mounted])

Upvotes: 2

Singhi John
Singhi John

Reputation: 347

React doesn't care how you use the state. So printing the age has no difference from putting the age in some logic computing. Eslint did right.

Upvotes: 0

Elder
Elder

Reputation: 1514

It says the dependency is missing because you do use age inside your useEffect, even if it's just for printing it out, so eslint probably believes you should add age do the dependency list.

useEffect(() => {
    console.log("simulate componentDidMount, age:", age); //age is being used here
  }, []);

Upvotes: 2

Related Questions