André Krosby
André Krosby

Reputation: 1146

React useState stuck after setting localStorage as initial state

I'm trying to create a shopping cart with React Hooks that saves in the local storage and gets retrieved when reloading the browser.

Everything pretty much works the way I want it to, but after I reload the browser and retrieve the localStorage-data, the item state won't update anymore. The cart object looks identical before and after reloading.

My cart context provider looks like this:

  const { itemList } = useContext(ItemContext)

  const [cart, setCart] = useState(() => {
    const localData =
      localStorage.getItem('cart');
    return localData !== null
      ? JSON.parse(localData)
      : [];
  });

  console.log(cart)

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

  const addItem = id => {
    let addedItem = itemList.find(item => item.id === id)
    let addedItemExists = cart.find(item => item.id === id)
    if (addedItemExists) {
      addedItem.quantity += 1
      setCart([...cart]);
    } else {
      addedItem.quantity = 1
      setCart([...cart, addedItem]);
    }
  };

(the itemList is a dummy data list with three items)

I've also tried to fix this by using a reducer, but I got the same result.

I've only been using React and JS for a couple of weeks, so I'm sorry if this is a noobie-question.

Upvotes: 0

Views: 4094

Answers (5)

aquinq
aquinq

Reputation: 1448

When you want to update your state partially, you need to use setState's first argument, representing the previous state

setCart((prev) => ([...prev]));
...
setCart((prev) => ([...prev, addedItems]));

instead of using its current value.

Now, your addItem function looks buggy in case addedItemExists is true, you don't seem to update the local state but rather itemList (you just update cart with its current value).

Maybe you should try the following :

const addItem = (id) => {
  const addedItem = itemList.find(item => item.id === id);
  const addedItemExists = cart.some(item => item.id === id);
  if (addedItemExists) {
    setCart((prev) => prev.map((item) => (
      item.id === id
        ? { ...item, quantity: item.quantity + 1 }
        : item
    )));
  } else {
    setCart((prev) => ([ ...prev, { ...addedItem, quantity: 1 } ]));
  }
}

Upvotes: 1

gdh
gdh

Reputation: 13682

You are just passing a function inside useState without calling it

Just call the function.

const { itemList } = useContext(ItemContext);

const initialStateFun = () => {
    const localData = localStorage.getItem("cart");
    return localData !== null ? JSON.parse(localData) : [];
  }
const [cart, setCart] = useState(initialStateFun()); //<--- call the fun

console.log(cart);

...

Also, if you want to go even simpler then just use ternary

useState(localStorage.getItem('cart') !== null ? JSON.parse(localData) : []);


Upvotes: -1

kibitzer
kibitzer

Reputation: 1

so, you are setting cart initially. (in the useState). Try doing it in the useEffect. this is just for clean code. I made a change in the if-else part.

  const { itemList } = useContext(ItemContext)

  const [cart, setCart] = useState([]);

  useEffect(() => {
    const localData = localStorage.getItem('cart');
    setCart(localData && localData.length > 0 ? JSON.parse(localData): []);
  }, [])

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

  const addItem = id => {
    let addedItem = itemList.find(item => item.id === id)
    let addedItemExists = cart.find(item => item.id === id)
    if (addedItemExists) {
      addedItem.quantity += 1
      setCart(cart => [...cart]);
    } else {
      addedItem.quantity = 1
      setCart(cart => [...cart, addedItem]);
    }
  };

Upvotes: 0

Red Baron
Red Baron

Reputation: 7652

try this instead:

const [cart, setCard] = useState(JSON.parse(localStorage.getItem(localData)))

or you could try:

const [cart, setCard] = useState(JSON.parse(localStorage.getItem(localData) : []))

then use:

cart && cart.map

when you want to map over it as cart will be null if doesn't exist in localStorage

Upvotes: -1

furkan kolsuz
furkan kolsuz

Reputation: 1

Try like this instead the way you do

const [cart, setCart] = useState([]);

 useEffect(() => {
    const localData =
      localStorage.getItem('cart');
    return localData !== null
      ? JSON.parse(localData)
      : [];
  }, [] )

Upvotes: 0

Related Questions