In reactjs and nextjs constructor getting Reference Error: localstorage is not defined

In reactjs and nextjs constructor getting Reference Error: localstorage is not defined

我在 reactjs 中制作系统 jsonwebtoken 并使用 nextjs。当我 运行 浏览器中的 localStorage 代码未定义时,我发现了问题。

这是我在文件中的代码 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

我从未接触过 nextjs,但我猜它相当于 Nuxt.js。因此,当您尝试在客户端访问本地存储时,它会进行服务器端渲染。

为此您需要使用 componentDidMount()。举个例子

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

编辑:

否则你可以试试 process.browser

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

constructorcomponentWillMount 生命周期挂钩上,服务器仍在渲染组件。另一方面,localStorage 作为浏览器 Window 全局的一部分存在,因此您只能在呈现组件时使用它。因此,您只能在 componentDidMount 生命周期挂钩上访问 localStorage。您可以定义一个空状态,并在可以开始调用 localStorage 时更新 componentDidMount 上的状态,而不是在构造函数上调用 localStorage。

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
  });
}

正如大家已经提到的,NextJS 同时在客户端和服务器上运行。在服务器上,没有 localStorage,因此 undefined 错误。

但是,另一种解决方案是在访问 localStorage 之前检查服务器上的 nextjs 是否 运行。即

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

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

除了@SILENT 所说的,这对我有用

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

Window 对象和 Localstorage 在 Nextjs 构建时将不可用。所以你需要在浏览器中检查代码是否为运行。如果你在 React hooks 中 运行 你不需要这样做,因为在 React 中 hooks 总是 运行 浏览器端。

只需将这两个实用函数添加到您的 nextjs 项目中即可。

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

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

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

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

我需要在 NextJS 中从 localStorage 读取一个令牌并将其添加到 axios 实例 header。它在组件之外,所以我使用 IIFE 实践来确保在客户端中:

(function(){
  if(typeof window !== "undefined"){
    AxiosInstance.defaults.headers.common.Authorization = `Bearer ${localStorage.getItem('TOKEN_KEY')}`
  }
})()

我创建了一个函数 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,
    },
  };