I am working on a react shopping e-commerce website and i am using useContext and useReducer to set my cart state but each time i add to cart and reload the page my cart clears and reinitialize
each time it sets the state on reload it reinitialise it and i need the data to persist
MY CART STATE
const CartState = ({ children }) => {
let items = [];
const initialState = {
showCart: false,
products: items,
cartItems: [],
};
const { q } = useQuery({
queryKey: ["products"],
queryFn: async () => {
const data = await getDocs(collection(db, "/products"));
data.docs.forEach((doc) => {
let key = doc.id;
let item = doc.data();
items.push({ key, item });
});
},
});
const [state, dispatch] = useReducer(CartReducer, initialState);
const addToCart = (item) => {
dispatch({ type: ADD_TO_CART, payload: item });
};
const showHideCart = () => {
dispatch({ type: SHOW_HIDE_CART });
};
const removeItem = (id) => {
dispatch({ type: REMOVE_ITEM, payload: id });
};
return (
<ShopContext.Provider
value={{
showCart: state.showCart,
products: state.products,
cartItem: state.cartItems,
addToCart,
showHideCart,
removeItem,
}}
>
{children}
</ShopContext.Provider>
);
};
MY USEREDUCER COMPONENT
import { SHOW_HIDE_CART, ADD_TO_CART, REMOVE_ITEM } from "../types";
const CartReducer = (state, action) => {
switch (action.type) {
case SHOW_HIDE_CART: {
return { ...state, showCart: !state.showCart };
}
case ADD_TO_CART: {
return { ...state, cartItems: [...state.cartItems, action.payload] };
}
case REMOVE_ITEM: {
return {
...state,
cartItems: state.cartItems.filter((item) => item.id !== action.payload),
};
}
default:
return state;
}
};
export default CartReducer;
To persist the cart state across page reloads, you can use the browser's localStorage to save the cart data. Here's how you can modify your CartState component to achieve this:
import React, { useEffect, useReducer } from "react";
import { getDocs, collection } from "firebase/firestore";
import { db } from "../firebase";
import { useQuery } from "react-query";
import CartReducer from "./CartReducer";
const CartState = ({ children }) => {
// Load cartItems from localStorage if available, or initialize to an empty array
const cartItemsFromStorage = localStorage.getItem("cartItems");
let items = cartItemsFromStorage ? JSON.parse(cartItemsFromStorage) : [];
const initialState = {
showCart: false,
products: [], // Assuming this is set by the query and does not need to persist
cartItems: items,
};
const { q } = useQuery({
queryKey: ["products"],
queryFn: async () => {
const data = await getDocs(collection(db, "/products"));
const products = data.docs.map((doc) => ({
key: doc.id,
item: doc.data(),
}));
return products;
},
});
const [state, dispatch] = useReducer(CartReducer, initialState);
// Save cartItems to localStorage whenever it changes
useEffect(() => {
localStorage.setItem("cartItems", JSON.stringify(state.cartItems));
}, [state.cartItems]);
const addToCart = (item) => {
dispatch({ type: ADD_TO_CART, payload: item });
};
const showHideCart = () => {
dispatch({ type: SHOW_HIDE_CART });
};
const removeItem = (id) => {
dispatch({ type: REMOVE_ITEM, payload: id });
};
return (
<ShopContext.Provider
value={{
showCart: state.showCart,
products: state.products,
cartItem: state.cartItems,
addToCart,
showHideCart,
removeItem,
}}
>
{children}
</ShopContext.Provider>
);
};
This modification adds a useEffect hook that listens for changes in the cartItems state and saves it to localStorage. It also initializes the cartItems state from localStorage if available. This way, the cart items will persist across page reloads.