3

I have a useEffect hook with two functions inside of it, the first (fetchImages) gets all of the user images stored in firebase storage.

The second (loadImages) awaits for the fetchImages and sets the image into a state array. The problem is that the images array is returning empty unless you go to a different page and come back...then the array is filled with image urls.

Im not sure if something is wrong with my useEffect hook or my placement of async await, or something else. The if check for currentUser is because currentUser returns as null on first load.

const [images, setImages] = useState([]); // All user images from storage
useEffect(() => {
    if (currentUser) {
        const fetchImages = async () => {
            setLoading(true)
            const result = await storage.ref(`images/${currentUser.id}`).listAll();
            console.log(result)
            const urlPromises = result.items.map((imageRef) =>
                imageRef.getDownloadURL()
            );
            console.log(urlPromises)
            return Promise.all(urlPromises);
        };

        const loadImages = async () => {
            const images = await fetchImages();
            setImages(images);
            setLoading(false);
        };
        loadImages();
    }
    console.log(loading)
}, []);
console.log(images, image)

The currentUser userContext file

export const UserContextProvider = ({ children }) => {
    const [currentUser, setUser] = useState(null);
    // const [currentUser, setUser] = useState('');
    
    useEffect(() => {
        let unsubscribeFromAuth = null;
        unsubscribeFromAuth = auth.onAuthStateChanged(async userAuth => {
            if (userAuth) {
                const userRef = await createUserProfileDocument(userAuth);

                userRef.onSnapshot(snapShot => {
                    setUser({
                        id: snapShot.id,
                        ...snapShot.data()
                    });
                });
            } else {
                setUser(null)
            }
        });

        return () => {
            unsubscribeFromAuth();
        };
    }, [])
    // console.log(unsubscribeFromAuth)

    const toggleUser = () => {
        auth.signOut()
            .then(() => {
                window.localStorage.clear();
            })
            .then(() => {
                setUser(null)
            })
            .catch(e => console.log('There was a error:'(e)))
    }
4
  • 1
    "currentUser is because currentUser returns as null on first load", that is the issue. You could make a promise returning function that works with onAuthStateChanged and only execute this function once that resolves with a valid user. Commented Dec 7, 2021 at 22:52
  • 2
    Probably you should fix currentUser first by making sure that the page can load if and only if currentUser is set Commented Dec 7, 2021 at 23:00
  • Thank you for commenting @Alexander Staroselsky, ive been banging my head on a wall with this. Ill try to implement that now Commented Dec 7, 2021 at 23:01
  • 1
    For a promise-based approach, see stackoverflow.com/questions/70075205/… Commented Dec 8, 2021 at 0:17

1 Answer 1

2

Add currentUser to the useEffect hook's dependency array. When the currentUser state updates you want the side-effect to be fetching the related images, or clearing them out.

const [images, setImages] = useState([]); // All user images from storage

useEffect(() => {
  if (currentUser) {
    const fetchImages = async () => {
      const result = await storage.ref(`images/${currentUser.id}`).listAll();
      const urlPromises = result.items.map((imageRef) =>
        imageRef.getDownloadURL()
      );
      return Promise.all(urlPromises);
    };

    const loadImages = async () => {
      setLoading(true);
      try {
        const images = await fetchImages();
        setImages(images);
      } catch(error) {
        // handle error, log it, show message, etc...
      }
      setLoading(false);
    };
    loadImages();
  } else {
    setImages([]);
  }
}, [currentUser]);
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.