Mapping the state of an array results on empty array upon first render. (React js, Redux saga, Firebase storage)

Viewed 69

EDIT --- SOLVED

Finally figured it out. The forEach loop is not asynchronous, I replaced it with a traditional loop and that solved my issue !

export const listImagesSagafied = async (listRef) => {
 const list = await listRef.listAll(); const listItems = list.items; const imgList = [];
for (let i = 0; i < list.items.length; i++) {
    const galleryImage = {}
    const downloadUrl = await listItems[i].getDownloadURL()
    galleryImage.name = listItems[i].name
    galleryImage.url = downloadUrl
    imgList.push(galleryImage)
}

return imgList;
};

ORIGINAL QUESTION BELOW

Goal: Fetch image urls from firebase storage, and list them in the "Gallery" page when the gallery page is opened.

Issue: Clicking Gallery results in a blank page, but clicking it once more will render the images. Clicking on contact and then back to gallery will again render a blank page in gallery . Video https://vimeo.com/583902534

Question: How can I make it so the gallery images render upon clicking on the "Gallery" nav button ?

Code below, I tried to make it as concise as possible without leaving out any code relevant to the issue.

GALLERY COMPONENT

import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';

import { fetchGalleryStart } from '../../redux/gallery/gallery.actions';

import './gallery.styles.css';

const Gallery = () => {
    const dispatch = useDispatch();
    const gallery = useSelector(state => state.gallery.galleryImages);

    useEffect(() => {
        dispatch(fetchGalleryStart('test-images'))
    }, [])

    return (
        <div>
            <div className='page center-page'>

                {<h1>Gallery Length: {gallery.length}</h1>}
                {gallery &&
                    gallery.map((img) => (
                        <div key={img.name} className='gallery-image-container'>
                            <img src={img.url} alt={img.name}></img>
                        </div>
                    ))
                }
            </div>
        </div>
    )
}

REDUX ACTIONS

import GalleryActionTypes from './gallery.types';

export const fetchGalleryStart = (storageRef) => ({
    type: GalleryActionTypes.FETCH_GALLERY_START,
    payload: storageRef,
})

export const fetchGallerySuccess = (galleryItems) => ({
    type: GalleryActionTypes.FETCH_GALLERY_SUCCESS,
    payload: galleryItems,
})

export const fetchGalleryFailure = (error) => ({
    type: GalleryActionTypes.FETCH_GALLERY_FAILURE,
    payload: error,
})

REDUX REDUCER

    import GalleryActionTypes from './gallery.types';
    
    const INITIAL_STATE = {
        galleryImages: null,
        isFetching: false,
        error: null,
    }
    
    const galleryReducer = (state = INITIAL_STATE, action) => {
        switch (action.type) {
            case GalleryActionTypes.FETCH_GALLERY_START:
                return {
                    ...state,
                    isFetching: true,
                }
    
            case GalleryActionTypes.FETCH_GALLERY_SUCCESS:
                return {
                    ...state,
                    isFetching: false,
                    galleryImages: action.payload,
                }
            case GalleryActionTypes.FETCH_GALLERY_FAILURE:
                return {
                    ...state,
                    isFetching: false,
                    error: action.payload,
                }
    
            default: return state;
        }
    };

export default galleryReducer;

REDUX SAGAS

import { put, takeLatest, call, all } from 'redux-saga/effects';

import GalleryActionTypes from './gallery.types';
import { fetchGallerySuccess, fetchGalleryFailure } from './gallery.actions';
    import { firestorage, listImagesSagafied } from '../../firebase/firebase-utils';
    
    function* getGalleryItems({ payload }) {
        try {
            const storageRef = firestorage.ref();
            const listRef = yield storageRef.child(payload);
            const images = yield call(listImagesSagafied, listRef)
    
            yield put(fetchGallerySuccess(images));
        } catch (error) {
            yield put(fetchGalleryFailure(error));
        }
    };
    
    export function* fetchGalleryItemsStart() {
        yield takeLatest(GalleryActionTypes.FETCH_GALLERY_START, getGalleryItems);
    };
    
    export function* gallerySagas() {
        yield all([
            call(fetchGalleryItemsStart),
        ])
    };

FIREBASE FUNCTION FOR FETCHING STORAGE ITEMS

export const listImagesSagafied = (listRef) => {
    const imgList = []
    listRef.listAll()
        .then((res) => {
            res.items.forEach((itemRef) => {
                const shopItem = {};
                shopItem.name = itemRef.name;

                itemRef.getDownloadURL()
                    .then((url) => {
                        shopItem.url = url
                        imgList.push(shopItem)
                    })
            });
        })
        .catch((error) => { console.log(error) });

    return imgList;
};
0 Answers
Related