Search code examples
javascriptreactjsreact-redux-firebase

Why does my HTML not display when I iterate through the populated array?


I am currently working with react, redux, and firebase to display a list of available books for sale. I have successfully populated an array with all the information I want to display and updated the state for redux with this information. However, the HTML does not change from a blank screen.

I have posted some relevant code below.

import React, { Component } from 'react';
import NavBar from './NavBar'
import {populate} from '../actions'
import {useSelector, useDispatch} from 'react-redux' 


const ItemList = () => {
    const itemList = useSelector(state => state.listReducer);
    const dispatch = useDispatch();
    if (!itemList.isLoaded) {
        dispatch(populate());
    }


    //Displays all items for sale
    return( 
        <div>
          <header>
              <div className='wrapper'>
              </div>
          </header>
          <div className='container'>
            <section className='display-item'>
                <div className="wrapper">
                  <ul>
                    {itemList.isLoaded ? itemList.items.map((item) => {
                      return (
                        <li key={item.id}>
                          <h3 key={item.title}>{item.title}</h3>
                          <p key={item.author}>Author: {item.author}
                            <button key={"button:" + item.id}>See item details</button>
                          </p>
                        </li>
                      )
                    }) : null}
                  </ul>
                </div>
            </section>
          </div>
        </div>
      );
}

export default ItemList

Reducer code below

const initialState = {
    items: [],
    isLoaded: false,
}


const listReducer = (state=initialState,action) => {
    switch (action.type) {
        case 'POPULATE-LIST':
            return {   
                items: action.payload,
                isLoaded: true,
            }

        case 'ADD-ITEM':
            let newState = state.slice();
            newState.push(action.payload);
            return newState


        default: {
            return state;
        }
    }
}

Action method below

export const populate = () => (
    dispatch, 
    getState, 
    {getFirebase}) => {
        const firebase = getFirebase();
        let items = [];
        const itemsRef = firebase.firestore().collection("items").doc("all-items").collection("books");
        itemsRef.get().then(documentSnapshot => {
            documentSnapshot.forEach(doc => {
            const item = doc.data();
            items.push(item);            
            })   
        }).then(dispatch({type: 'POPULATE-LIST', payload: items}))

    }

In addition, I am currently also using redux-thunk


Solution

  • Try putting 'let items' within the promise call to firebase, and then instead of putting the dispatch in a separate promise, put it outside of the forEach loop but within the initial promise. The code will look like this:

    export const populate = () => (
        dispatch, 
        getState, 
        {getFirebase}) => {
            const firebase = getFirebase();
            const itemsRef = firebase.firestore().collection("items").doc("all-items").collection("books");
            itemsRef.get().then(documentSnapshot => {
                const items = [];
                documentSnapshot.forEach(doc => {
                    const item = doc.data();
                    items.push(item);            
                })
                dispatch({type: 'POPULATE-LIST', payload: items})
            });
    
        } ```