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

能否在Server Components中使用Context值?Store适配方案求助

解决Server Components中无法访问Store的问题

你的核心问题在于:客户端用React Context实现的Store模式依赖客户端Hooks,而Server Components无法调用这些Hooks;同时服务端不能用单例Store(会导致多请求数据串用)。下面是几个可行的解决方案:

方案1:在Server Components中直接实例化Store

既然RootLayout已经在服务端拿到了session,你可以把session传递给子Server Components,在组件内部创建Store实例:

首先修改RootLayout,将session作为props传递给子组件:

// app/layout.tsx
export default async function RootLayout({ children }) {
  const client = createDatabaseAndAuthClient();
  const session = await getSession(client);
  
  // 将session传给子Server Component
  const childWithProps = typeof children === 'function' 
    ? children({ session }) 
    : React.cloneElement(children, { session });

  return (
    <html>
      <body>
        <AppProvider session={session}>
          {childWithProps}
        </AppProvider>
      </body>
    </html>
  );
}

然后在Server Component中直接创建Store并使用:

// app/page.tsx (Server Component)
import { createStore } from "@/lib/store";

export default async function Home({ session }) {
  const store = createStore(session);
  const user = await store.getUser();
  return <>{`Hello from the server, ${user.name}!`}</>;
}

方案2:抽离核心逻辑,做客户端/服务端双版本Store

把Store的API交互核心逻辑抽成独立的纯类/函数,客户端用Context包装,服务端直接实例化调用,避免代码重复:

先创建核心逻辑文件:

// lib/store-core.ts
// 这里是纯业务逻辑,不依赖React
export class StoreCore {
  private session: Session;

  constructor(session: Session) {
    this.session = session;
  }

  async getUser() {
    // 这里写你的API/数据库调用逻辑
    return await fetch(`/api/users/${this.session.userId}`).then(res => res.json());
  }

  // 其他业务方法...
}

客户端Store(用Context包装):

// lib/store.tsx
"use client";
import { createContext, useContext, useMemo } from "react";
import { StoreCore } from "./store-core";

const StoreContext = createContext<StoreCore | undefined>(undefined);

export function AppProvider({ session, children }) {
  const store = useMemo(() => new StoreCore(session), [session]);
  return <StoreContext.Provider value={store}>{children}</StoreContext.Provider>;
}

export const useApp = () => {
  const store = useContext(StoreContext);
  if (!store) throw new Error("useApp必须在AppProvider内部使用");
  return store;
};

服务端专用Store工具:

// lib/server-store.ts
import { StoreCore } from "./store-core";
import { createDatabaseAndAuthClient, getSession } from "./auth";

export async function createServerStore() {
  const client = createDatabaseAndAuthClient();
  const session = await getSession(client);
  return new StoreCore(session);
}

然后在Server Component中使用:

// app/page.tsx
import { createServerStore } from "@/lib/server-store";

export default async function Home() {
  const store = await createServerStore();
  const user = await store.getUser();
  return <>{`Hello from the server, ${user.name}!`}</>;
}

方案3:直接传递数据(适合简单场景)

如果不需要复杂的Store方法,直接在RootLayout中获取数据,传递给子组件即可:

// app/layout.tsx
export default async function RootLayout({ children }) {
  const client = createDatabaseAndAuthClient();
  const session = await getSession(client);
  const store = createStore(session);
  const user = await store.getUser();

  return (
    <html>
      <body>
        <AppProvider session={session}>
          {React.cloneElement(children, { user })}
        </AppProvider>
      </body>
    </html>
  );
}

// app/page.tsx
export default async function Home({ user }) {
  return <>{`Hello from the server, ${user.name}!`}</>;
}

关键注意事项

  • 禁止用单例Store:服务端处理多并发请求,单例会导致不同用户的session串用,引发数据安全问题。
  • Server Components不能用客户端Hooks:useContext、useMemo等Hooks仅能在客户端组件中使用。
  • 核心逻辑复用:把API/数据库交互的纯逻辑抽离,避免客户端和服务端重复写相同代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 13:13:12