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

Next.js中服务端组件向客户端组件传递API缓存数据时遇React子元素错误的解决方案咨询

Next.js中服务端组件向客户端组件传递API缓存数据时遇React子元素错误的解决方案咨询

我来帮你分析并解决这个问题~你遇到的错误本质是对Next.js服务端组件的返回值要求理解有误,咱们一步步梳理清楚:

问题根源

你现在的ServerComponent.js返回了一个{props: {data}}对象,这是Next.js旧版(比如getServerSideProps)的页面数据返回格式,但服务端组件本身是标准React组件,必须返回JSX元素或null,不能直接返回这种props对象。React尝试渲染这个普通对象时,就会抛出「Objects are not valid as a React child」的错误。

而且你的嵌套逻辑也有点绕——客户端组件作为父组件包裹服务端组件的方式,没法直接拿到服务端组件的数据,正确的思路应该是让服务端组件获取数据后,把数据传递给客户端组件使用。

解决方案

下面给你两种符合Next.js 13+ App Router规范的实现方式,都能实现「服务端缓存API数据,传给客户端组件渲染」的需求:

方式一:服务端组件作为父组件传递数据(推荐)

这种方式逻辑最清晰,让服务端组件负责数据获取,再把数据作为props传给客户端组件:

  1. 修改ServerComponent.js:获取数据后直接渲染客户端组件并传递数据
import { API } from "../utils/api";
import Home from './clientComponent';

export default async function Server() {
  const data = await getData();
  // 服务端组件直接渲染客户端组件,把data作为props传入
  return <Home data={data} />;
}

async function getData() {
  // fetch在Next.js服务端组件默认是force-cache,自动缓存数据
  // 可通过next选项调整缓存策略,比如缓存一天
  const res = await fetch(API.pages.retrieve(1), {
    next: { revalidate: 86400 }
  });
  
  if (!res.ok) {
    throw new Error('Failed to fetch data');
  }
  
  return res.json();
}
  1. 简化page.js:直接引入服务端组件即可(page.js默认是服务端组件)
// page.js
import Server from './ServerComponent'

export default function Page() {
  return <Server />;
}
  1. 修改clientComponent.js:接收data props并渲染内容
'use client'
import Image from 'next/image'
import styles from './page.module.css'
import Typography from '@mui/material/Typography';

export default function Home({ data }) {
  // 处理数据,注意加可选链避免空值报错
  const set1 = data?.textblockset?.find(item => item.id === 1);
  
  return (
    <main className={styles.main}>
      {set1?.textblock?.map((item, index) => (
        <div key={index}>
          {item.block_icon && (
            <Image
              src={item.block_icon}
              alt="icon"
              width={50}
              height={50}
              loading="lazy"
            />
          )}
          <Typography paragraph fontWeight="bold">
            {item.block_title}
          </Typography><br/>
          <Typography>
            {item.block_content}
          </Typography>
        </div>
      ))}
    </main>
  )
}

方式二:保持嵌套结构,服务端组件返回带数据的JSX

如果你想保留「客户端组件包裹服务端组件」的结构,可以让服务端组件返回包含数据的JSX元素,比如自定义一个数据容器:

  1. 修改ServerComponent.js:
import { API } from "../utils/api";

export default async function Server() {
  const data = await getData();
  // 返回一个包含数据的自定义元素,客户端组件可以通过children.props拿到数据
  return <DataContainer data={data} />;
}

// 定义一个简单的容器组件
function DataContainer({ data }) {
  return <>{data}</>;
}

async function getData() {
  const res = await fetch(API.pages.retrieve(1), {
    next: { revalidate: 86400 }
  });
  
  if (!res.ok) {
    throw new Error('Failed to fetch data');
  }
  
  return res.json();
}
  1. 修改clientComponent.js:从children中提取数据
'use client'
import Image from 'next/image'
import styles from './page.module.css'
import Typography from '@mui/material/Typography';

export default function Home({ children }) {
  const data = children.props.data;
  const set1 = data?.textblockset?.find(item => item.id === 1);
  
  return (
    <main className={styles.main}>
      {set1?.textblock?.map((item, index) => (
        <div key={index}>
          {item.block_icon && (
            <Image
              src={item.block_icon}
              alt="icon"
              width={50}
              height={50}
              loading="lazy"
            />
          )}
          <Typography paragraph fontWeight="bold">
            {item.block_title}
          </Typography><br/>
          <Typography>
            {item.block_content}
          </Typography>
        </div>
      ))}
    </main>
  )
}

关键提示

  • 关于缓存:fetch在Next.js服务端组件中默认使用force-cache策略,数据会被自动缓存,不会每次客户端访问都调用API。你可以通过next.revalidate设置缓存有效期,或者next.tags实现增量更新。
  • 空值处理:渲染数据时记得加可选链(?.),避免数据未加载或格式异常时抛出错误。

备注:内容来源于stack exchange,提问作者Matthias

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.21 14:54:40