Skip to content
Advertisement

Can someone help me understand how async + await + useEffect work in React?

I have a React app built with the Minimal template and I’m trying to follow along with one of their tutorials, in order to create a Redux slice that feeds some data to a custom component. The data itself is collected from Firebase. Below is my code:

firebase.js – helper

export function getDocuments(col) {
    const colRef = collection(db, col);
    const q = query(colRef, where('uid', '==', auth.currentUser.uid));

    getDocs(q).then((snap) => {
        const data = snap.docs.map((d) => ({ id: d.id, ...d.data() }));
        return data;
    });
   // return [1,2,3]
}

product.js – Redux slice

export function getProducts() {
    return async (dispatch) => {
        dispatch(slice.actions.startLoading());
        try {
            const products = await getDocuments('products');
            dispatch(slice.actions.getProductsSuccess(products));
        } catch (error) {
            dispatch(slice.actions.hasError(error));
        }
    };
}

ProductList.js – component

const dispatch = useDispatch();
const { products } = useSelector((state) => state.client);

useEffect(() => {
    dispatch(getProducts());
}, [dispatch]);

useEffect(() => {
    if (products.length) {
        // setTableData(products);
    }
}, [products]);

If I console log data in the helper function (firebase.js), I get the values I expect, once the promise is resolved/fulfilled. However, if I console.log clients in the product.js slice or later in the component, I get undefined. I assume my problem is not being able to understand how async + await + useEffect work together in order to fix this. My assumption is that I am trying to access the value before the promise is resolved and therefore before the helper function returns it. I confirmed that by returning a simple array [1, 2, 3] in my helper function as a test.

I think I am missing something fundamental here (I am not very experienced with React and JS in general and still learning things on the go). Can someone help me understand what am I doing wrong?

Thank you!

Advertisement

Answer

With await you can await the fulfillment or rejection of a promise, but your getDocuments Function does not return a promise. Change the last line of the function to the following:

return getDocs(q).then((snap) => {
    const data = snap.docs.map((d) => ({ id: d.id, ...d.data() }));
    return data;
});
Advertisement