【问题标题】:Localstorage with React States带有 React 状态的本地存储
【发布时间】:2021-06-01 07:48:29
【问题描述】:

我正在使用 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'
    }

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

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 在页面重新加载之前不会再次更新,但我该如何实现呢?

【问题讨论】:

    标签: reactjs local-storage


    【解决方案1】:

    问题

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

    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 获取值可能会返回 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);
      }
    }, []);
    

    【讨论】:

    • 我不会使用 const [cart, setCart] = useState(initializeState()) 因为我使用的是带有 firebase 的 localStorage,所以如果用户没有登录,我会使用 localStorage。跨度>
    • @TurtlesS 我明白了。这是否意味着您问题中的代码不是您的实际代码的准确表示?一旦挂载,您可以继续使用useEffect 挂钩设置状态,重要的问题是来自存储API 的潜在null 值。我更新了我的答案以反映使用 useEffect 钩子。
    • 不,无论我使用 firebase,您的解决方案都能完美运行。
    • 但是这样做重要吗?或者也许我可以这样做,但如果用户登录它就会被覆盖?
    • 另外,我对直接变异状态不太熟悉,那么我如何才能从购物车数组中删除一个 caritem 呢?
    【解决方案2】:

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

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

    然后在useEffect 以及incrementQty 的末尾调用loadCart()

    编辑

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

    【讨论】:

    • OP也应该涵盖getItem返回null的情况
    猜你喜欢
    • 2018-07-14
    • 2017-06-11
    • 1970-01-01
    • 1970-01-01
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-05
    相关资源
    最近更新 更多