NodeJS 在React和Next.js构造函数中,我得到“引用错误:localstorage未定义”

ubof19bj  于 2023-06-05  发布在  Node.js
关注(0)|答案(7)|浏览(473)

我在React中创建了一个系统jsonwebtoken,并使用了Next.js。我在浏览器中运行代码时发现了一个问题,即 “localStorage is not defined”。我该怎么解决?
这是我在 * AuthStudentContext.js * 文件中的代码:

import React from 'react'
import axios from 'axios'

const axiosReq = axios.create()
const AuthStudentContext = React.createContext()

export class AuthStudentContextProvider extends React.Component {

    constructor() {
        super()
        this.state = {
            students: [],
            student: localStorage.getItem('student') || {},
            token: localStorage.getItem('token') || "",
            isLoggedIn: (localStorage.getItem('student' == null)) ? false : true
        }
    }

    login = (credentials) => {
        return axiosReq.post("http://localhost:4000/api/login", credentials)
            .then(response => {
                const { token } = response.data
                localStorage.setItem("token", token)

                this.setState({
                    token,
                    isLoggedIn: true
                })

                return console.log(response)
            })
    }

它显示错误“localStorage is not defined”。

6ss1mwsb

6ss1mwsb1#

正如大家已经提到的,Next.js在客户端和服务器端都运行。在服务器上,没有任何localStorage,因此出现了undefined错误。
但是,另一种解决方案是在访问localStorage之前检查Next.js是否在服务器上运行。即,

const ISSERVER = typeof window === "undefined";

if(!ISSERVER) {
    // Access localStorage
    ...localStorage.get...
}
jgovgodb

jgovgodb2#

constructorcomponentWillMount生命周期钩子中,服务器仍然呈现组件。另一方面,localStorage作为浏览器的 window global的一部分存在,因此只能在呈现组件时使用它。因此,您只能在componentDidMount生命周期钩子中访问localStorage。不需要在构造函数中调用localStorage,您可以定义一个空状态,并在可以开始调用localStorage时更新componentDidMount中的状态。

constructor() {
  super()
  this.state = {
    students: [],
    student: undefined
    token: undefined,
    isLoggedIn: undefined
  };
}

componentDidMount() {
  this.login();
  this.setState({
    student: localStorage.getItem('student') || {},
    token: localStorage.getItem('token') || "",
    isLoggedIn: (localStorage.getItem('student' == null)) ? false : true
  });
}
jum4pzuy

jum4pzuy3#

我从来没有接触过Next.js,但我猜它相当于Nuxt.js。因此,当您尝试访问客户端的本地存储时,它会进行服务器端渲染。
您需要使用componentDidMount()来完成此操作。下面是一个例子:

componentDidMount(){
   localStorage.setItem('myCat', 'Tom');
   alert("Tom is in the localStorage");
}

或者,你可以用process.browser试试:

if (process.browser) {
   localStorage.setItem("token", token);
}
jfewjypa

jfewjypa4#

除了Silent说的,这对我来说很有效:

React.useEffect(() => {
    if (localStorage) {
        const getLocalState = localStorage.getItem("headless");
        console.log("LocalState: ", getLocalState)
    }
}, []);
rbl8hiat

rbl8hiat5#

在构建Next.js时,window 对象和Localstorage将不可用。因此,您需要检查代码是否在浏览器中运行。如果你在React hooks中运行,你不需要这样做,因为hooks总是在React中运行浏览器端。
只需将这两个实用程序函数添加到Next.js项目即可。

export const isBrowser = (): boolean => {
  return typeof window !== 'undefined'
}

export const nextLocalStorage = (): Storage | void => {
  if (isBrowser()) {
    return window.localStorage
  }
}

然后你可以像这样在你的代码中使用它:

nextLocalStorage()?.setItem('user', JSON.stringify(user))
7rtdyuoh

7rtdyuoh6#

我创建了一个函数getLocalStorageItem,并在useEffect中使用所需的键名调用了它。从localStorage获取值后,将其保存在一个状态(即currentUser)中,并在initialState中使用它。

const [currentUser, setCurrentUser] = useState({});

  const getLocalStorageItem = (key) => {
    return typeof window !== undefined
      ? window.localStorage.getItem(key)
      : null;
  };

  useEffect(() => {
    setCurrentUser({
      token: getLocalStorageItem("token"),
      refreshToken: getLocalStorageItem("refreshToken"),
    });
  }, []);

  const initialState = {
    auth: {
      isLoggedIn: true,
      currentUser: currentUser,
    },
  };
lzfw57am

lzfw57am7#

localStorage仅在客户端可用。因此,如果您尝试访问localStorage到getItemsetItem,Next.js将抛出错误。
相反,在组件内部,使用useEffect钩子访问第一个客户端渲染器上的localStorage

useEffect(() => {
  localStorage.setItem("abc", "def");
}, []);

相关问题