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

Next.js 13使用layout.js全局上下文:子组件无法同步用户状态

解决Next.js 13 App目录下全局用户状态同步问题

你当前的问题是导航栏能从JWT解析显示用户名,但子组件loginsuccess/page.jsx无法同步获取用户状态。核心原因是全局状态的数据源不一致:RootLayout维护了自己的user状态,却直接把它传给MyProvider的value,但MyProvider本身内部还有独立的value状态,两者没有绑定,导致上下文的状态不会跟随RootLayout的user更新。

以下是修正方案:

1. 调整Context结构,让Provider统一管理用户状态

修改context/MyContext.js,把用户状态的初始化和更新逻辑移到Provider内部,确保所有组件共享同一个状态源:

import { createContext, useState, useEffect } from "react";
import Cookies from "js-cookie";

const MyContext = createContext({
  user: null,
  setUser: () => {},
  isLoading: true,
});

export const MyProvider = ({ children }) => {
  const [user, setUser] = useState(null);
  const [isLoading, setIsLoading] = useState(true);

  // 从JWT Cookie获取用户信息的逻辑移到Provider内部
  const getUserFromJWTCookie = async () => {
    const authToken = Cookies.get("token");
    if (!authToken) return null;
    
    try {
      const response = await fetch("/api/session", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({ token: authToken }),
      });
      const responseData = await response.json();
      return responseData.username || null;
    } catch (error) {
      console.error("Failed to fetch user:", error);
      return null;
    }
  };

  useEffect(() => {
    const initUser = async () => {
      const fetchedUser = await getUserFromJWTCookie();
      setUser(fetchedUser);
      setIsLoading(false);
    };
    initUser();
  }, []);

  return (
    <MyContext.Provider value={{ user, setUser, isLoading }}>
      {children}
    </MyContext.Provider>
  );
};

export default MyContext;

2. 重构RootLayout,依赖Context状态

先创建app/providers.jsx统一管理Provider:

"use client";
import { MyProvider } from "@/context/MyContext";

export function Providers({ children }) {
  return <MyProvider>{children}</MyProvider>;
}

再修改app/layout.jsx,不再维护独立状态,直接从Context获取用户信息并处理跳转:

"use client";

import "./globals.css";
import Link from "next/link";
import { useContext, useEffect } from "react";
import { useRouter } from "next/navigation";
import MyContext from "@/context/MyContext";
import { Providers } from "./providers";

// 提取导航栏组件,简化RootLayout逻辑
const Navbar = () => {
  const { user } = useContext(MyContext);
  return (
    <nav className="bg-gray-800 text-white p-4">
      <ul className="flex justify-center space-x-4">
        <li className="hover:bg-gray-700 rounded-md p-2">
          <Link href="/show">
            <h1 className="text-xl font-semibold">Shows</h1>
          </Link>
        </li>
        <li className="hover:bg-gray-700 rounded-md p-2">
          <Link href="/user">
            <h1 className="text-xl font-semibold">Users</h1>
          </Link>
        </li>
        {user && (
          <li className="hover:bg-gray-700 rounded-md p-2">
            <Link href="/loginsuccess">
              <h1 className="text-xl font-semibold">{user}</h1>
            </Link>
          </li>
        )}
      </ul>
    </nav>
  );
};

export default function RootLayout({ children }) {
  const { user, isLoading } = useContext(MyContext);
  const router = useRouter();

  useEffect(() => {
    if (!isLoading && !user) {
      router.replace("/logintest");
    }
  }, [user, isLoading, router]);

  // 加载状态下显示过渡内容
  if (isLoading) return <div>Loading...</div>;

  return (
    <Providers>
      <html lang="en">
        <body>
          <Navbar />
          <main>{children}</main>
        </body>
      </html>
    </Providers>
  );
}

3. 简化子组件loginsuccess/page.jsx

直接从Context获取用户状态,无需额外的state和useEffect:

"use client";

import { useContext } from "react";
import MyContext from "@/context/MyContext";

const ProtectedPage = () => {
  const { user } = useContext(MyContext);

  if (!user) return <div>Please log in first.</div>;

  return <div>Welcome! {user}</div>;
};

export default ProtectedPage;

关键修改说明

  • 单一状态源:把用户状态的管理完全交给MyProvider,所有组件通过Context获取状态,确保状态同步。
  • 加载状态处理:新增isLoading状态,避免未完成用户获取时出现空值或跳转错误。
  • 解耦逻辑:将导航栏提取为独立组件,让RootLayout职责更清晰。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 14:44:55