Next.js13使用Render Props遇TypeError: children is not a function求助
问题:React 18/Next.js 13中Render Props报错“children is not a function”
首页代码
export default async function Home() { // console.log(data) it is populated const { data } = getAllArts(); return ( <main className="flex min-h-screen flex-col items-center justify-between p-24"> <div className="z-10 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex"> <ArtList arts={data}> {(art: Art) => <ArtCard key={art.id} art={art} disabled={false} />} </ArtList> </div> </main> ); }
ArtList组件代码(使用Render Props)
interface ArtListProps { arts: Art[]; // using React.ReactNode causes type is not callable error children: FunctionComponent; } export default function ArtList({ arts, children }: ArtListProps) { return ( <section className="grid md:grid-cols-1 lg:grid-cols-2 gap-4 mb-5"> {arts.map((art) => children(art))} </section> ); }
报错信息
- error src/components/ui/art/ArtList.tsx (15:25) @ children - error TypeError: children is not a function at eval (./src/components/ui/art/ArtList.tsx:12:35) at Array.map (<anonymous>) at ArtList (./src/components/ui/art/ArtList.tsx:12:24) at stringify (<anonymous>)
版本对比
- 可正常运行版本:
"next": "11.1.0", "react": "17.0.2", "react-dom": "17.0.2", - 当前使用版本:
"next": "13.4.19", "react": "18.2.0", "react-dom": "18.2.0",
解决方法
问题根源是Next.js 13 App Router对children的处理逻辑变化,加上TypeScript类型定义错误,分两步修复:
- 修正TypeScript类型定义
FunctionComponent是组件类型,不是渲染函数的正确类型。应该定义为接收Art参数并返回React节点的函数:
import type { ReactNode } from 'react'; interface ArtListProps { arts: Art[]; children: (art: Art) => ReactNode; }
- 适配App Router的children处理逻辑
在Next.js 13 App Router中,传入组件的children会被自动包装为ReactNode(即使是函数),直接调用会报错。推荐两种解决方案:
方案一:用显式props传递渲染函数(更清晰安全)
修改组件调用方式,把渲染函数作为render props传入,而非children:
// 首页调用代码 <ArtList arts={data} render={(art: Art) => <ArtCard key={art.id} art={art} disabled={false} />} /> // ArtList组件修改 interface ArtListProps { arts: Art[]; render: (art: Art) => ReactNode; } export default function ArtList({ arts, render }: ArtListProps) { return ( <section className="grid md:grid-cols-1 lg:grid-cols-2 gap-4 mb-5"> {arts.map((art) => render(art))} </section> ); }
方案二:强制断言children为函数(仅兼容旧写法时用)
如果坚持用children传递函数,可通过类型断言绕过包装问题:
export default function ArtList({ arts, children }: ArtListProps) { const renderFn = children as (art: Art) => ReactNode; return ( <section className="grid md:grid-cols-1 lg:grid-cols-2 gap-4 mb-5"> {arts.map((art) => renderFn(art))} </section> ); }
- 额外验证
确保getAllArts()返回的data是有效数组,避免因arts为undefined导致map执行出错。
内容的提问来源于stack exchange,提问作者Yilmaz
相关产品推荐
相关产品推荐

