Reputation: 1146
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
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
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
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
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
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