You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Next.js搭建基于Axios的认证流程时遇到localStorage未定义错误的求助

解决Next.js中Server Error: ReferenceError: localStorage is not defined

这问题我在Next.js项目里踩过好几次!核心原因非常明确:Next.js的服务端渲染(SSR)阶段是在Node.js环境运行的,而localStorage是浏览器专属的API,Node.js里根本不存在这个对象。你现在的代码在reducer最顶部直接调用localStorage.getItem,服务端执行这段代码的时候自然就会抛出ReferenceError。

下面给你两种可行的解决方案,按需选择:

方案1:在reducer中判断客户端环境再读取localStorage

最简单的临时修复方式,就是在读取localStorage之前先判断当前是否处于浏览器环境:

import { LOGIN_SUCCESS, LOGIN_FAIL, LOGOUT } from "../actions/types";

// 只有在浏览器环境下才尝试读取localStorage
const user = typeof window !== 'undefined' ? JSON.parse(localStorage.getItem("user")) : null;
const initialState = user ? { isLoggedIn: true, user } : { isLoggedIn: false, user: null };

export default function (state = initialState, action) {
  const { type, payload } = action;
  switch (type) {
    case LOGIN_SUCCESS:
      return {
        ...state,
        isLoggedIn: true,
        user: payload.user,
      };
    case LOGIN_FAIL:
      return {
        ...state,
        isLoggedIn: false,
        user: null,
      };
    case LOGOUT:
      return {
        ...state,
        isLoggedIn: false,
        user: null,
      };
    default:
      return state;
  }
}

这种方式改动最小,但有个小缺点:reducer不再是纯函数,依赖了外部环境(浏览器的window对象),不符合Redux的设计原则。

方案2:在客户端组件中初始化状态(更推荐)

更规范的做法是让reducer保持纯函数,把读取localStorage的逻辑放到客户端组件里,再通过action同步到Redux store:

第一步:修改reducer的初始状态

把初始状态设为默认的未登录状态,让reducer不依赖任何外部环境:

import { LOGIN_SUCCESS, LOGIN_FAIL, LOGOUT } from "../actions/types";

// 纯初始状态,不依赖外部API
const initialState = { isLoggedIn: false, user: null };

export default function (state = initialState, action) {
  const { type, payload } = action;
  switch (type) {
    case LOGIN_SUCCESS:
      return {
        ...state,
        isLoggedIn: true,
        user: payload.user,
      };
    // 合并LOGIN_FAIL和LOGOUT的逻辑,减少重复代码
    case LOGIN_FAIL:
    case LOGOUT:
      return {
        ...state,
        isLoggedIn: false,
        user: null,
      };
    default:
      return state;
  }
}

第二步:在根组件中读取localStorage并同步状态

在你的_app.js(或者项目的根布局组件)里,使用useEffect钩子(确保只在客户端执行)读取localStorage,然后dispatch action更新store:

import { useEffect } from 'react';
import { useDispatch } from 'react-redux';
// 假设你有一个loginSuccess的action,用来同步已登录用户状态
import { loginSuccess } from '../actions/authActions';

function MyApp({ Component, pageProps }) {
  const dispatch = useDispatch();

  useEffect(() => {
    // useEffect的回调函数只会在客户端执行,安全访问localStorage
    const storedUser = localStorage.getItem('user');
    if (storedUser) {
      try {
        const user = JSON.parse(storedUser);
        dispatch(loginSuccess({ user }));
      } catch (err) {
        // 处理解析失败的情况,比如localStorage里的内容损坏
        localStorage.removeItem('user');
      }
    }
  }, [dispatch]);

  return <Component {...pageProps} />;
}

export default MyApp;

这种方式更符合Redux的设计理念,同时还能避免服务端渲染和客户端hydration不匹配的问题,推荐使用。

内容的提问来源于stack exchange,提问作者Beckham

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 19:57:34