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

Next.js路由跳转时Zustand Store未定义问题求助

问题分析与解决方案

问题根源

你的核心问题出在闭包捕获旧状态和HOC中状态订阅方式上:

  • 直接地址栏访问时,组件挂载前Zustand Store已完成初始化,能正确获取状态;
  • 登录跳转是客户端软导航,组件挂载时,useEffect空依赖导致捕获的是组件挂载瞬间的Store快照(此时可能因为React状态批量更新机制,Store还未完成更新),进而出现authStore为undefined的情况。

修复方案

1. 优化路由守卫HOC,使用Selector订阅特定状态

修改ProtectedRoute,用Zustand的Selector仅订阅user状态,避免闭包问题,并添加正确的依赖项:

"use client";

import React, { useEffect } from "react";
import { useAuthStore } from "@/store/authStore";
import { useRouter } from "next/navigation";

const ProtectedRoute = <P extends object>(WrappedComponent: React.ComponentType<P>) => {
  const ComponentWithAuth = (props: P) => {
    // 仅订阅user状态,减少不必要的重渲染
    const user = useAuthStore((state) => state.user);
    const router = useRouter();

    useEffect(() => {
      if (!user) {
        router.push("/");
      }
    }, [user, router]); // 依赖user和router,确保状态变化时重新验证

    // 用户未登录时不渲染受保护组件,避免崩溃
    if (!user) {
      return <div>加载中...</div>; // 可替换为自定义加载组件
    }

    return <WrappedComponent {...props} />;
  };

  // 用memo优化,避免无意义的重渲染
  return React.memo(ComponentWithAuth);
};

export default ProtectedRoute;

2. 规范登录逻辑中Store的使用方式

确保在组件内通过useAuthStore获取setUserData,而非直接操作Store实例(如果你的Store是通过create创建的):

"use client";

import { useAuthStore } from "@/store/authStore";
import { useRouter } from "next/navigation";

const LoginForm = () => {
  const router = useRouter();
  // 通过Selector获取setUserData
  const setUserData = useAuthStore((state) => state.setUserData);

  const submitForm = async (data: LoginFormValues) => {
    try {
      await login(data);
      const user = await getMe();
      setUserData(user);
      // 利用微任务确保Store状态更新完成后再跳转
      setTimeout(() => {
        router.push("/app");
      }, 0);
    } catch (e) {
      console.error("登录失败:", e);
    }
  };

  // 表单渲染逻辑
  return <div>...</div>;
};

3. 补充Store定义检查

确保你的authStore.ts定义正确,状态初始化正常:

// @/store/authStore.ts
import { create } from "zustand";

// 定义用户类型
interface User {
  id: string;
  name: string;
  // 其他用户字段
}

interface AuthState {
  user: User | null;
  setUserData: (user: User) => void;
}

export const useAuthStore = create<AuthState>((set) => ({
  user: null,
  setUserData: (user) => set({ user }),
}));

关键说明

  • 使用Selector订阅特定状态是Zustand的最佳实践,既能减少不必要的重渲染,又能避免闭包捕获旧值的问题;
  • useEffect添加user依赖后,会在用户状态变化时自动重新执行权限验证,无需手动监听;
  • 用户未登录时返回加载组件,可避免渲染受保护组件导致的崩溃。

内容的提问来源于stack exchange,提问作者martin Čonto

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 00:00:58