16

我在 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 未定义

4

5 回答 5

16

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

但是,另一种解决方案是在访问localStorage. IE

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

if(!ISSERVER) {
 // Access localStorage
 ...localStorage.get...
}
于 2020-08-31T00:27:26.917 回答
14

在生命周期钩子constructorcomponentWillMount,服务器仍在渲染组件。另一方面,localStorage作为浏览器全局窗口的一部分存在,因此您只能在渲染组件时使用它。因此,您只能在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
  });
}
于 2019-12-31T06:31:33.733 回答
9

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

您将需要为此使用componentDidMount()。这里有一个例子

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

编辑:

否则你可以试试process.browser

if (process.browser) {
   localStorage.setItem("token", token);
}
于 2019-12-31T06:24:00.223 回答
4

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

 React.useEffect(() => {
    if (localStorage) {
      const getLocalState = localStorage.getItem("headless");
      console.log("LocalState: ", getLocalState)
    }
  }, []);
于 2021-09-09T13:31:31.290 回答
0

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

只需将这两个实用函数添加到您的 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))
于 2022-03-01T14:25:48.563 回答