Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React useEffect hook does not fire when prop dependency changes

I am using a useEffect hook to make an API call depending on data from a photos prop being passed in.

const ImageCarousel = ({ src, photos }) => {
  const [photoList, setPhotos] = useState([]);
  const storageRef = firebase.storage().ref();
  console.log("photos prop:", photos);

  const getImage = photoId => {
    return new Promise((resolve, reject) => {
      storageRef
        .child("images/" + photoId)
        .getDownloadURL()
        .then(url => resolve(url))
        .catch(error => reject(error));
    });
  };

  useEffect(() => {
    console.log("trigger");
    Promise.all(
      photos.map(async photoId => {
        const url = await getImage(photoId);
        return url;
      })
    )
      .then(photoUrls => {
        setPhotos(photoUrls);
      })
      .catch(e => console.log(e));
  }, [photos]);

return (...)
}

I have passed the photos prop into the dependency array of my useEffect hook, so it should fire when the photos prop changes. I can see that the prop is indeed changing in the console, but my useEffect hook does not fire when the prop change comes through. This is what appears in my console:

Console logs

Why is the useEffect not firing twice? From my understanding it should fire when the component renders the first time, and fire again every time the photos prop changes.

like image 240
laythq Avatar asked Dec 14 '22 09:12

laythq


2 Answers

Try to make sure your photos prop is immutable, meaning, you send a new array each time there is a change and not mutating the array

like image 81
NirG Avatar answered Dec 26 '22 12:12

NirG


This may not be the most correct answer, but I've tried this and it works. Hat tip to https://dev.to/stephane/how-to-make-sure-useeffect-catches-array-changes-fm3

useEffect(() => {
  console.log("trigger");
  Promise.all(
    photos.map(async photoId => {
      const url = await getImage(photoId);
      return url;
    })
  )
  .then(photoUrls => {
    setPhotos(photoUrls);
  })
  .catch(e => console.log(e));
}, [JSON.stringify(photos])); // stringify the array used as the trigger, and it'll catch the change
like image 27
user101289 Avatar answered Dec 26 '22 10:12

user101289