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

NextJS 13中Zustand状态无法持久化的问题排查求助

问题分析与解决方案

核心问题原因

  • Zustand状态未持久化:当前的Zustand store仅存于客户端内存,页面刷新或导航时状态会丢失,服务端组件完全无法访问客户端内存中的状态。
  • 服务端组件无法直接读取客户端状态:AdminDashboard作为服务端组件,运行在服务器环境,无法获取客户端Zustand存储的用户数据。
  • Root Layout跳转逻辑缺陷:页面初次加载时Zustand初始状态为null,会直接触发跳转,即便用户已登录(因状态未持久化)。

可行解决方案

1. 给Zustand添加持久化中间件

启用Zustand的persist中间件,将状态存入localStorage,确保页面刷新后状态不丢失。

修改userDataStore.ts:

import { UserData, UserStore } from "@/types";
import { create } from "zustand";
import { persist } from "zustand/middleware";

const userDataStore = create<UserStore>()(
  persist(
    (set) => ({
      tenantId: null,
      userId: null,
      accessToken: null,
      refreshToken: null,
      setUserData: (userData: UserData) => set(userData),
      clearUserData: () => set({ tenantId: null, userId: null, accessToken: null, refreshToken: null })
    }),
    {
      name: "user-data-storage", // localStorage存储键名
      storage: localStorage, // 可选sessionStorage
    }
  )
);

export default userDataStore;

2. 服务端组件获取用户状态的正确方式

服务端组件需通过Cookie传递认证信息,在服务端校验用户身份:

修改AdminDashboard服务端组件:

import { cookies } from 'next/headers';
import { GetUsers } from "@/api/user";

export default async function AdminDashboard() {
  const cookieStore = cookies();
  const accessToken = cookieStore.get('accessToken')?.value;

  // 服务端校验token有效性,无有效token则重定向
  if (!accessToken) {
    return Response.redirect(new URL('/', request.url));
  }

  const users = await GetUsers(accessToken); // 将token传入API请求
  return (
    <section>
      Hello Admin, total users: {users.length}
    </section>
  );
}

同时在登录成功后将token存入Cookie(客户端组件中操作):

// 在LoginComponent的handleSubmit中添加
const handleSubmit = async (email: string, password: string) => {
  setLoading(true);
  const loginAttemptData = await LoginApi(email, password);
  if (!loginAttemptData.isSuccess) {
    form.setErrors({
      [loginAttemptData.data.incorrectField]: loginAttemptData.message,
    });
  }
  if (loginAttemptData.isSuccess) {
    setUserData(loginAttemptData.data);
    // 客户端存入Cookie,配置安全属性
    document.cookie = `accessToken=${loginAttemptData.data.accessToken}; path=/; max-age=86400; secure; SameSite=Lax`;
    document.cookie = `refreshToken=${loginAttemptData.data.refreshToken}; path=/; max-age=604800; secure; SameSite=Lax`;
  }
  setLoading(false);
};

3. 修复Root Layout的认证逻辑

避免初始状态为null时误跳转,仅在非登录页且状态为空时重定向:

修改RootLayout:

'use client'

import './globals.css'
import { usePathname } from 'next/navigation';
import { useRouter } from 'next/navigation'

import Provider from './provider'
import MainShell from '@/Components/AppShell'
import { useEffect, useState } from 'react';
import userDataStore from '@/Store/userData';

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  
  const pathname = usePathname()
  const router = useRouter()

  const { tenantId, userId } = userDataStore()
  
  const [hidden, setHidden] = useState(true);

  useEffect(() => {
    setHidden(pathname === '/');
    
    // 仅在非登录页且无用户状态时跳转
    if (pathname !== '/' && (!tenantId || !userId)) {
      router.replace("/");
    }
  }, [pathname, tenantId, userId]);

  return (
    <html lang="en">
      <body>
        <Provider>
          <MainShell hidden={hidden}>
            {children}
          </MainShell>
        </Provider>
      </body>
    </html>
  )
}

4. 客户端组件访问状态的正确方式

若将AdminDashboard改为客户端组件,需添加"use client"指令并正确订阅Zustand状态:

"use client";

import userDataStore from "@/Store/userData"
import { GetUsers } from "@/api/user"
import { useEffect, useState } from "react";

export default function AdminDashboard() {
  const { accessToken } = userDataStore();
  const [users, setUsers] = useState([]);

  useEffect(() => {
    if (accessToken) {
      const fetchUsers = async () => {
        const data = await GetUsers(accessToken);
        setUsers(data);
      };
      fetchUsers();
    }
  }, [accessToken]);

  return (
    <section>
      Hello Admin, total users: {users.length}
    </section>
  )
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 15:47:13