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

Next.js 14服务器组件能否用useCallback/useMemo?遇await错误如何解决?

问题解答:Next.js 14 服务器组件中使用useCallback/useMemo报错

核心结论

React的useCallback、useMemo等钩子完全不支持在服务器组件中使用,这是React和Next.js App Router的核心设计规范,不是可规避的“问题”,而是用法错误。

报错原因

  1. 服务器组件运行在服务器端,没有React客户端运行时环境,钩子依赖客户端的组件状态管理、渲染生命周期等机制,服务器端根本不存在这些上下文。
  2. 你代码中的async组件在App Router里默认就是服务器组件,加上await语句后,组件的渲染流程进入异步阶段,React的钩子上下文会直接销毁,所以会抛出Cannot read properties of null (reading 'useCallback')这类错误。

解决方案

要满足公司组件一致性要求,同时符合Next.js架构规范,正确的做法是拆分组件边界:

1. 拆分服务器组件与客户端组件

  • 服务器组件:负责异步数据获取、静态内容渲染,不使用任何React钩子。
  • 客户端组件:添加'use client'指令声明,专门处理交互逻辑、使用钩子,接收服务器组件传递的props数据。

2. 修改后的代码示例

服务器组件(Test.tsx)

// 无需添加'use client',默认是服务器组件
export const Test = async () => {
  const getAsyncStuff = async () => 'async stuff';
  const asyncData = await getAsyncStuff();

  // 将异步数据传递给客户端组件
  return <TestClient asyncData={asyncData} />;
};

客户端组件(TestClient.tsx)

'use client'; // 必须添加此指令,声明为客户端组件

import { useCallback, useMemo } from 'react';

type TestClientProps = {
  asyncData: string;
};

export const TestClient = ({ asyncData }: TestClientProps) => {
  // 这里可以正常使用useCallback
  const getStuff = useCallback(() => 'stuff', []);
  // 正常使用useMemo
  const stuff = useMemo(() => 'stuff', []);

  return (
    <div>
      <p>异步数据:{asyncData}</p>
      <p>{getStuff()}</p>
      <p>{stuff}</p>
    </div>
  );
};

3. 组件一致性的保障方案

如果公司要求组件写法统一,可以制定规范:

  • 所有需要使用钩子的逻辑,统一放在带'use client'的客户端组件中。
  • 服务器组件专注于数据层和静态渲染,通过props将数据传递给客户端组件,保持数据层与交互层的分离,同时保证组件写法的一致性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 01:52:42