Search code examples
reactjsgoogle-cloud-firestorereduxreact-hooksredux-toolkit

Redux and firebase passing reacthooks


My problem here is I'm trying to collect the data in react hooks and then I want to pass it in my initial state of redux which can be shown like this:

import { createSlice } from '@reduxjs/toolkit'
import { doc, onSnapshot, setDoc } from 'firebase/firestore'
import { useState } from 'react'
import { useEffect } from 'react'
import { db } from '../lib/firebase'
import { itemsCollectionRef } from '../lib/firebase-collection'


function Items(params) {
    const [UsersData,setUsersData] = useState([])
    
    useEffect(() => {
        const unsubscribe = onSnapshot(itemsCollectionRef,snapshot => {
            setUsersData(snapshot.docs.map((doc,idx) => {
                return {
                    ...doc.data(),
                    name:doc.data().name
                }
            }))
        })
        return () => {
            unsubscribe()
        }
    },[])

    return UsersData
}
//Here I'm trying to pass all the data in firebase in the itemsSlice

export const itemsSlice = createSlice({
    name:"items",
    initialState:{ value: Items },
    reducers:{
        addItem: (state,action) => {
            state.value.push(action.payload)
            const { id,name,message,shape } = action.payload

            setDoc(doc(db,`items`,`${action.payload.name}-${id}`),{
              name:name,message:message,shape:shape
            })
            .then( res => {})
            .catch(err => {})

        },
        ...

    }
})

So as you see I'm trying to pass my Usersdata in the itemsSlice but the thing is that my Items function is passing all the format of code which is kind of wrong. It supposed to pass the array UsersData what did I miss here? Can anyone help me? thanks :)


Solution

  • You will need to dispatch an action to populate theitems state after the app/component has mounted and rendered and then run the useEffect hook to make the asynchronous documents request. For this you'll need to provide valid initial state for the slice, and add a new case reducer to initialize the state to a specific value.

    const initialState = { value: [] };
    
    export const itemsSlice = createSlice({
      name: "items",
      initialState,
      reducers: {
        initialize: (_, action) => ({
          state.value = action.payload;
        }),
        ...
      }
    });
    

    Next will be some useEffect hook that makes the firebase call to get the documents and dispatches an action to initialize the items state. The reason I say some useEffect hook is because it seems Items is defined like it's a custom hook, but it's not called like a React hook.

    import { useDispatch } from 'react-redux';
    import itemsSlice from '../items.slice';
    
    ...
    
    const dispatch = useDispatch();
    
    useEffect(() => {
      const unsubscribe = onSnapshot(itemsCollectionRef, snapshot => {
        const userData = snapshot.docs.map((doc, idx) => ({
          ...doc.data(),
          name: doc.data().name
        }));
        dispatch(itemsSlice.initialize(userData));
      });
    
      return unsubscribe;
    }, []);
    

    The above logic could be abstracted into a custom hook and then imported and called from a React function component.