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

Next14如何在全局上下文共享服务端获取的用户认证信息?

Next14 无需'use client'实现用户信息全局共享方案

核心逻辑

Next14 App Router 支持服务器组件层面的上下文传递,完全绕开客户端的useEffect和'use client'指令,下面提供两种可行方案:


方案一:React Context + 根布局注入(全局共享)

  1. 定义用户上下文
    创建上下文文件,无需添加客户端指令:
// app/context/userContext.tsx
import { createContext, useContext, ReactNode } from 'react';

type User = {
  id: string;
  name: string;
  // 补充你的用户字段
} | null;

const UserContext = createContext<User | undefined>(undefined);

export function UserProvider({ children, user }: { children: ReactNode; user: User }) {
  return <UserContext.Provider value={user}>{children}</UserContext.Provider>;
}

export function useUser() {
  const context = useContext(UserContext);
  if (context === undefined) {
    throw new Error('useUser 必须在 UserProvider 内部使用');
  }
  return context;
}
  1. 根布局中获取用户并注入上下文
    根布局是服务器组件,可直接调用你的getUser方法,将用户数据传入上下文:
// app/layout.tsx
import { UserProvider } from './context/userContext';
import { cookies } from 'next/headers';

async function getUser() {
  const cookieStore = cookies();
  // 注意:无需手动设置cookie头,credentials: 'include'会自动携带当前请求的Cookie
  const response = await fetch(`http://localhost:3005/api/user`, {
    method: 'GET',
    credentials: 'include',
    headers: {
      'Content-Type': 'application/json',
    },
  });
  
  if (!response.ok) {
    return null; // 处理未认证场景
  }
  const user = await response.json();
  return user;
}

export default async function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  const user = await getUser();
  
  return (
    <html lang="zh-CN">
      <body>
        <UserProvider user={user}>
          {children}
        </UserProvider>
      </body>
    </html>
  );
}
  1. 任意组件中使用用户数据
  • 服务器组件直接调用useUser(),无需任何客户端指令:
// app/components/Nav.tsx
import { useUser } from '../context/userContext';

export default async function Nav() {
  const user = useUser();
  
  return (
    <nav>
      {user ? (
        <span>欢迎,{user.name}</span>
      ) : (
        <a href="/login">登录</a>
      )}
    </nav>
  );
}
  • 若需在客户端交互组件中使用,仅需在组件顶部添加'use client'即可(仅交互组件需要,纯展示组件保持服务器组件属性)。

方案二:服务器组件Props传递(轻量共享)

如果不需要全局上下文,可通过根布局获取用户后,逐层通过Props传递给目标组件,全程无需客户端代码:

// app/layout.tsx
async function getUser() { /* 同方案一的getUser实现 */ }

export default async function RootLayout({ children }) {
  const user = await getUser();
  return (
    <html lang="zh-CN">
      <body>
        {React.cloneElement(children as React.ReactElement, { user })}
      </body>
    </html>
  );
}

// app/page.tsx
export default function Home({ user }) {
  return (
    <div>
      <Nav user={user} />
      {/* 页面其他内容 */}
    </div>
  );
}

// app/components/Nav.tsx
export default function Nav({ user }) {
  return (
    <nav>
      {user ? <span>欢迎,{user.name}</span> : <a href="/login">登录</a>}
    </nav>
  );
}

重要修正提示

你当前的getUser方法存在错误:cookie: cookieStore是无效写法,cookies()返回的是Next.js的CookieStore对象,无需手动在请求头中设置,credentials: 'include'会自动携带当前请求的Cookie。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 13:41:39