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

在Next.js App Router中如何将服务端组件数据存入Jotai

问题解决思路与代码修改

报错原因解析

你的代码触发报错的核心原因有两个:

  1. Jotai的useAtom依赖React的useEffect客户端钩子,而Next.js App Router中组件默认是服务端组件,不允许使用客户端钩子。
  2. 服务端直接调用categoriesAtom.set(data)无效:Jotai的默认状态存储在服务端和客户端是隔离的,服务端没有React上下文支持直接修改客户端状态。

解决方案:服务端取数 + 客户端Jotai初始化

我们需要拆分逻辑:服务端组件负责获取数据,客户端组件负责管理Jotai状态并渲染,同时通过全局Provider实现全站状态共享。

步骤1:定义全局Atom

创建单独的原子文件(比如src/atoms/categories.ts),统一管理分类状态:

import { atom } from 'jotai';

// 定义分类原子,初始值为空数组
export const categoriesAtom = atom([]);

步骤2:根Layout服务端取数并初始化Store

在根layout.tsx(服务端组件)中获取数据,并用Jotai的Store实现服务端到客户端的状态同步:

import { createStore } from 'jotai/vanilla';
import { Provider } from 'jotai';
import { categoriesAtom } from '@/atoms/categories';
import HeaderLogged from '@/components/Header/HeaderLogged';

// 服务端获取分类数据
async function fetchCategories() {
  const res = await fetch('https://api.escuelajs.co/api/v1/categories', { 
    cache: 'force-cache' // 根据需求调整缓存策略
  });
  if (!res.ok) throw new Error('获取分类数据失败');
  return res.json();
}

export default async function RootLayout({ children }: { children: React.ReactNode }) {
  const categories = await fetchCategories();
  
  // 创建全局Store并设置初始值
  const store = createStore();
  store.set(categoriesAtom, categories);

  return (
    <html lang="zh-CN">
      <body>
        {/* 全局注入Jotai Store,确保全站客户端组件都能访问状态 */}
        <Provider store={store}>
          <HeaderLogged />
          {children}
        </Provider>
      </body>
    </html>
  );
}

步骤3:客户端组件使用Jotai状态

修改HeaderLogged.tsx,添加use client标记转为客户端组件,直接使用全局状态:

'use client'; // 必须放在文件最顶部,标记为客户端组件

import { useAtom } from 'jotai';
import { categoriesAtom } from '@/atoms/categories';
import MainNav2Logged from './MainNav2Logged';

export interface HeaderLoggedProps {}

const HeaderLogged = () => {
  const [categories] = useAtom(categoriesAtom);

  return (
    <div className="nc-HeaderLogged sticky top-0 w-full z-40 ">
      <MainNav2Logged />
      {categories.map((el) => (
        <p key={el.id}>is it here? {el.name}</p>
      ))}
    </div>
  );
};

export default HeaderLogged;

关键注意事项

  • use client必须放在客户端组件的第一行,明确告知Next.js这是客户端组件。
  • 服务端fetch可以通过cache参数控制数据缓存策略,比如revalidate: 3600实现每小时刷新一次数据。
  • 通过全局Provider注入Store后,所有客户端组件都能通过useAtom访问分类状态,实现全站共享。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 12:52:30