Why is `useEffect` not re-running when the dependencies change?

Viewed 41

Background: I was trying to fetch all the links for a set of images, then fetch the real assets for images using the links fetched.

let imageLinks = [];

useEffect(() => {
    fetch("http://localhost:3001/video/1?offset=0&count=100")
        .then((res) => res.json())
        .then((res) => {
            imageLinks = res.frames;
        });
}, []);

useEffect(() => {
    Promise.all(
        imageLinks.map((link) =>
            fetch("http://localhost:3001/" + link).then((res) => res.json())
        )
    ).then((res) => console.log(res));

// update when the image links changed
}, [imageLinks]);

The last useEffect didn't seem to be working, even when imageLinks has been updated in the previous useEffect. Could anyone please tell me why is that?

1 Answers

In your example, imageLinks is just a variable inside the React component. If the component's prop or state was to change, the variable's value would be reset to [] on each re-render.

To keep React in sync with imageLinks current value, you would need to save it in state. To do this, you need to use useState.

In the example below, when setImageLinks is called it will get stored in React's state, the component will re-render and it will be passed to the effect. The effect will then check if imageLinks has changed and run the effect, if so:

const [imageLinks, setImageLinks] = React.useState([]);

useEffect(() => {
    fetch("http://localhost:3001/video/1?offset=0&count=100")
        .then((res) => res.json())
        .then((res) => {
            setImageLinks(res.frames);
        });
}, []);

useEffect(() => {
    Promise.all(
        imageLinks.map((link) =>
            fetch("http://localhost:3001/" + link).then((res) => res.json())
        )
    ).then((res) => console.log(res));

// update when the image links changed
}, [imageLinks]);

Further to this, it may simplify your code if you group your fetches together rather than having them as separate effects.

Related