具有 React 状态的本地存储

Localstorage with React States

我正在使用 Localstorage 和 States 更新用户的购物车,但在用户重新加载页面之前不会发生更新。我的代码如下所示:

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

useEffect(()=>{
    const data = localStorage.getItem('cart')
    setCart(JSON.parse(data))
 }, [])

我在页面加载时设置用户的购物车。

现在,当用户增加商品的数量时,例如,ONE 购物车商品将如下所示:

  const singleCartItem = {
    qty: 10,
    color: 'red'
    size: 's'
    productid: 'asdasd123213'
    }

这是我用来更新商品数量的函数:

const incrementQty = (type, id, qty) => {

   incart.forEach(el=>{
      if(el.id === id) {
         const index = incart.indexOf(el)
         incart[index].qty = qty + 1
         localStorage.setItem('cart', JSON.stringify(cart))
      }
   })     

 } 

问题来了。我知道 localStorage 在页面重新加载之前不会再次更新,但我该如何实现?

在 localStorage 中更新购物车后,只需像在 useEffect 中一样再次设置状态。在这种情况下,您可以创建一个新函数并重新使用它:

const loadCart = () => {
    const data = localStorage.getItem('cart') || []
    setCart(JSON.parse(data))
}

然后在 useEffectincrementQty 结束时调用 loadCart()

编辑

我在 localStorage.getItem 之后添加了 || [] 以防 returns 为 null,因此这种情况下的默认值将是一个空数组。

问题

主要问题是您正在改变本地状态而不是更新它。正是由于这种突变,您才t/can在重新加载页面并且重新获取您保留的购物车数据之前看不到“更新的”购物车。

const incrementQty = (type, id, qty) => {
  incart.forEach(el=>{
    if(el.id === id) {
       const index = incart.indexOf(el)
       incart[index].qty = qty + 1 // <-- state mutation
       localStorage.setItem('cart', JSON.stringify(cart))
    }
  })  
}

一个小问题是,如果之前没有存储任何内容,从 localStorage 获取值可能 return null。 storage getItem

解决方案

你不应该直接改变状态。将前一个状态浅复制到下一个状态,记住也要浅复制任何正在更新的嵌套状态。

您还应该将更新状态的行为与将其持久化到 localStorage 分离,为此使用 useEffect 挂钩。

const incrementQty = (type, id, qty) => {
  setCart(cart => cart.map(
    item => item.id === id ? {
      ...item,
      qty: item.qty + 1
    } : item,
  ));
}

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

我建议将本地购物车状态初始化抽象为一个函数。

const initializeState = () => ({
  cartItems: JSON.parse(localStorage.getItem("cart")) || [],
});

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

如果您需要继续使用 useEffect 挂钩来加载状态,首先从 localStorage 获取购物车状态,如果非空则更新 cart 状态。

useEffect(() => {
  const cartState = JSON.parse(localStorage.getItem("cart"));
  if (cartState) {
    setState(cartState);
  }
}, []);