Eva
Eva

Reputation: 467

React Hook useEffect has a missing dependency array

I'm using firebase database to store the data and I am mounting the data using the useEffect hook. But it gives me warning of missing dependency arrays.

Whenever I pass dependencies it goes into an infinite loop

const Channels = props => {
  const [channels, setChannels] = useState([]);
  const [firstLoad, setFirstLoad] = useState(false);

  useEffect(() => {
    let loadedChannels = [];

    firebase
      .database()
      .ref("channels")
      .on("child_added", snap => {
        loadedChannels.push(snap.val());
        setChannels(channels.concat(loadedChannels));
        setFirstLoad(true);
      });
  }, []);
}

Upvotes: 2

Views: 1833

Answers (1)

jered
jered

Reputation: 11581

Edit: Looking at it again, the reason you're getting that error is because you're closing over the initial value of channels when your useEffect() runs the first time. So channels really should be in your dependency array because when that value changes, you would want the new value to be reflected in the state updates from then on. You're sort of trying to get around it with the loadedChannels array which is a weird anti-pattern.

I would actually recommend that you tweak it to something like this. Note how setChannels is now called with a function, which takes the actual up to date value of channels as an argument and lets you update the value without it being out of date due to a closure.

Note also how the useEffect() function returns another function that removes the Firebase event listener when the component unmounts!

const Channels = props => {
  const [channels, setChannels] = useState([]);
  const [firstLoad, setFirstLoad] = useState(false);

  useEffect(() => {
    function onFirebaseUpdate(snap) {
      setChannels((previousChannelsValue) => {
        return previousChannelsValue.concat(snap.val())
      });
      setFirstLoad(true);
    }

    firebase
      .database()
      .ref("channels")
      .on("child_added", onFirebaseUpdate);

    // You'll want to remove this listener when the component unmounts...
    return function() {
      firebase
        .database()
        .ref("channels")
        .off("child_added", onFirebaseUpdate);
    }
  }, []);
}

If you still get a warning, it's probably because either firebase or setChannels are references in the function and should be considered for addition to the dependency array. But in this case you (hopefully) know what you're doing and what's going on and can ignore the warning.

Upvotes: 4

Related Questions