'React, cart with context and localstorage

I have a demo here

It's a cart with products that can be added to a cart and show a total.

I'm using context for the state as the products and cart are different components.

I'd like to use localstorage to storage the cart and total data so if the page is refreshed the cart data won't be lost.

I can store the data in the localstorage with

useEffect(() => {
    localStorage.setItem("cart", JSON.stringify(items));
    total();
  }, [items]); 
  

but I'm not sure how to use this when the page loads again.

I want a cart where I can add and delete products and have them stored in local storage, I'm not sure if using context is the best option or it might be better just using localstorge.

But anyway how can I use localstorage to load the cart and total data when the page is refreshed.



Solution 1:[1]

I've made few changes click here

You can simply add the below code in your carts.tsx file

const [isInitiallyFetched, setIsInitiallyFetched] = useState(false);    
const addItems = useContext(AddCartContext);

useEffect(()=>{
  let prev_items = JSON.parse(localStorage.getItem('cart')) || [];
  addItems(prev_items)
  setIsInitiallyFetched(true)
},[])

useEffect(() => {
  if(isInitiallyFetched){
    localStorage.setItem("cart", JSON.stringify(items));
    total();
  }
}, [items]);

make sure to import AddCartContext.

And in context.tsx

   <AddCartContext.Provider
      value={useCallback(item => {
        if (Array.isArray(item)) {
          setItems([...itemsRef.current, ...item]);
        } else {
          setItems([...itemsRef.current, item]);
        }
      }, [])}
    >

Now try refreshing the page, Your previous cart state will be restored.
Happy Coding...

Solution 2:[2]

Hi you can get localStorage data in the useEffect like this:

useEffect(() => {
  if(!items.length){
    const jsonItems = localStorage.getItem("cart");
    const localItems = JSON.parse(jsonItems);
    setItems(jsonItems)
  }
}, [items]);

And in case you want to read data from localStorage just the first time component renders you can do something like this:

const [avoidReading, setAvoidReading] = useState(false);

useEffect(() => {
  if (!items.length && !avoidReading) {
    const jsonItems = localStorage.getItem("cart");
    const localItems = JSON.parse(jsonItems);
    setItems(jsonItems);
  }
}, [items, avoidReading]);

but if you sure you want to use localStorage a better and cleaner way is to use useLocalStorage custom hook which is like useState but it can persist data through localStorage, read more about it here: https://usehooks.com/useLocalStorage/

all you need to do is replace useState in your Provider to useLocalStorage and you're good to go.

Solution 3:[3]

const cartfromlocalstorage = JSON.parse(localStorage.getItem('cart')) || '[]'

 useEffect(() => {
    localStorage.setItem("cart", JSON.stringify(cart))
  }, [cart]);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 Suraj Rao