skip to Main Content

I’m using the following code to store cart data into local storage

"use client";
import React, { useState, useEffect } from "react";
export default function Home() {
  const [cartItems, setCartItems] = useState([]);

  useEffect(() => {
    const cartItemsData = JSON.parse(localStorage.getItem("cartItems"));
    if (cartItemsData) {
      console.log("loaded cart items data", cartItemsData);
      setCartItems(cartItemsData);
    }
  }, []);

  useEffect(() => {
    console.log("storing cart items", JSON.stringify(cartItems));
    localStorage.setItem("cartItems", JSON.stringify(cartItems));
  }, [cartItems]);

  return <div>{JSON.stringify(cartItems)}</div>;
}

The issue I’m having is that when the page reloads, there is a race condition as it calls the use effect hook which pulls the data from local storage and after it calls the use effect hook with cartItems=[] from the initialisation of useState([]) which then wipes local storage and sets cartItems to [].

I tried loading the data from local storage in useState but I get an error as the window hasn’t loaded at that point.

How do I fix this?

Interestingly if I set useState(""), it seems to work ok as in this case, the setCartItems is called after the initial use effect fires.

3

Answers


  1. To fix this issue, you can initialize the state with a function that retrieves the data from localStorage only once when the component mounts. This avoids the problem of initializing with an empty array and then overwriting the state and localStorage.

    "use client";
    import React, { useState, useEffect } from "react";
    
    export default function Home() {
      // Initialize state with a function that retrieves data from localStorage
      const [cartItems, setCartItems] = useState(() => {
        const cartItemsData = localStorage.getItem("cartItems");
        return cartItemsData ? JSON.parse(cartItemsData) : [];
      });
    
      useEffect(() => {
        // This effect will run whenever cartItems changes, storing the new state in localStorage
        localStorage.setItem("cartItems", JSON.stringify(cartItems));
      }, [cartItems]);
    
      return <div>{JSON.stringify(cartItems)}</div>;
    }
    
    

    Another alternative

    useLocalStorageState from aHooks

    Login or Signup to reply.
  2. you can use this code for this issue

    "use client";
    import React, { useState, useEffect } from "react";
    export default function Home() {
      
      const cartItemsData = useMemo(JSON.parse(localStorage.getItem("cartItems")),[]);
    
      const [cartItems, setCartItems] = useState(cartItemsData??[]);
    
      useEffect(() => {
        localStorage.setItem("cartItems", JSON.stringify(cartItems));
      }, [cartItems]);
    
      return <div>{JSON.stringify(cartItems)}</div>;
    }
    
    Login or Signup to reply.
  3. When you initialize the cartItems’s state with an empty array ([]), the useEffect that read from localStorage will run after the initial render. This means the initial state will be an empty array, and the useEffect that writes to localStorage will immediately store this empty array before the useEffect that reads from localStorage can update the state with the actual data.

    On the other hand, when you initialize the cartItems’s state with an empty string (""), the initial state is not an empty array, so it do not trigger the same immediate overwrite behavior. This can cause the useEffect that reads from localStorage to run and set the state before the useEffect that writes to localStorage can overwrite it.

    The solutiuon can be to initialize state with localStorage data or an empty array if no data is found.

    const [cartItems, setCartItems] = useState(() => {
        // Check if running in the client
        if (typeof window !== 'undefined') {
          const cartItemsData = localStorage.getItem("cartItems");
          return cartItemsData ? JSON.parse(cartItemsData) : [];
        }
        return [];
      });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search