简体   繁体   English

在 NextJS 中刷新时 localStorage 重置为空

[英]localStorage resets to empty on refresh in NextJS

I have a shopping cart system in my next.js app using Context.我的 next.js 应用程序中使用 Context 有一个购物车系统。

I define my cart with useState :我用useState定义我的购物车:

const [cartItems, setCartItems] = useState([]);

Then I use useEffect to check and update the localStorage:然后我使用useEffect来检查和更新 localStorage:

useEffect(() => {
    if (JSON.parse(localStorage.getItem("cartItems"))) {
      const storedCartItems = JSON.parse(localStorage.getItem("cartItems"));
      setCartItems([...cartItems, ...storedCartItems]);
    }
  }, []);

  useEffect(() => {
    window.localStorage.setItem("cartItems", JSON.stringify(cartItems));
  }, [cartItems]);

This stores the items in localStorage fine, but when I refresh, it resets the cartItems item in localStorage to an empty array.这将项目存储在 localStorage 中,但是当我刷新时,它将 localStorage 中的cartItems项目重置为一个空数组。 I've seen a few answers where you get the localStorage item before setting the cart state but that throws localStorage is not defined errors in Next.我已经看到了一些答案,您在设置购物车 state 之前获得了 localStorage 项目,但这会在 Next 中引发localStorage is not defined错误。 How can I do this?我怎样才能做到这一点?

setCartItems sets the value of cartItems for the next render, so on the initial render it's [] during the second useEffect setCartItems为下一次渲染设置cartItems的值,因此在初始渲染时,它在第二次useEffect期间为[]

You can fix this by storing a ref (which doesn't rerender on state change) for whether it's the first render or not.您可以通过存储 ref(不会在 state 更改时重新渲染)来解决此问题,无论它是否是第一次渲染。

import React, { useState, useRef } from "react";

// ...

// in component

const initialRender = useRef(true);

useEffect(() => {
    if (JSON.parse(localStorage.getItem("cartItems"))) {
        const storedCartItems = JSON.parse(localStorage.getItem("cartItems"));
        setCartItems([...cartItems, ...storedCartItems]);
    }
}, []);

useEffect(() => {
    if (initialRender.current) {
        initialRender.current = false;
        return;
    }
    window.localStorage.setItem("cartItems", JSON.stringify(cartItems));
}, [cartItems]);

thanks to jamesmosier for his answer on gitHub感谢jamesmosier对 gitHub 的回答

The issue you are seeing is because localStorage (aka window.localStorage) is not defined on the server side.您看到的问题是因为 localStorage(又名 window.localStorage)未在服务器端定义。 Next server renders your components, so when that happens and it tried to access localStorage it can't find it.下一个服务器呈现您的组件,因此当发生这种情况并尝试访问 localStorage 时,它找不到它。 You'll have to wait until the browser renders it in order to use localStorage.您必须等到浏览器呈现它才能使用 localStorage。

full answer link here完整答案链接在这里

EDIT编辑

you can try this:你可以试试这个:

useEffect(() => {
    if (typeof window !== "undefined") {
      const storedCartItems = JSON.parse(localStorage.getItem("cartItems"));
      if(storedCartItems !== null) {
        setCartItems([...cartItems, ...storedCartItems]);
      }
    }
  }, []);

  useEffect(() => {
    if (typeof window !== "undefined") {
     window.localStorage.setItem("cartItems", JSON.stringify(cartItems));
    } 
  }, [cartItems]);

React never updates state immediately It's an asynchronous process, for example, if you console.log(stateValue) just after the setState() method you'll get prevState value in a log. React 从不立即更新 state 这是一个异步过程,例如,如果您在 setState() 方法之后使用 console.log(stateValue),您将在日志中获得 prevState 值。 You can read more about it here .你可以在这里阅读更多关于它的信息。

That is exactly happening here, you have called setState method inside the first useEffect, state has not updated yet by react and we're trying to update localStorage with the latest state value(for now it's [] since react has not updated the state yet).这正是在这里发生的,您在第一个 useEffect 中调用了 setState 方法,state 尚未通过 react 更新,我们正在尝试使用最新的 state 值更新 localStorage(现在它是 [],因为 react 尚未更新 state )。 that's why the localStorage value holds an empty array.这就是为什么 localStorage 值包含一个空数组的原因。

In your case, you can reverse the execution of useEffect as I have mentioned in the snippet, this would work perfectly as you expected since we've added the dependency in the useEffect.在您的情况下,您可以反转 useEffect 的执行,正如我在代码段中提到的那样,这将完全按照您的预期工作,因为我们已经在 useEffect 中添加了依赖项。

useEffect(() => {
    window.localStorage.setItem("cartItems", JSON.stringify(cartItems));
  }, [cartItems]);

useEffect(() => {
    if (JSON.parse(localStorage.getItem("cartItems"))) {
      const storedCartItems = JSON.parse(localStorage.getItem("cartItems"));
      setCartItems([...cartItems, ...storedCartItems]);
    }
  }, []);

PS: You can refer @Samathingamajig's answer as well PS:您也可以参考@Samathingamajig 的回答

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM