Next.js+TypeScript中如何以JSX形式传递组件作为Props?
解决Next.js+TypeScript中传递预渲染JSX组件的服务端错误
问题场景
在Next.js结合TypeScript的项目中,循环渲染数组项时,将<InboxIcon strokeWidth={6}/>这类预渲染的JSX元素存入数组并作为props传递,会触发服务端错误:「元素类型无效:期望字符串或类/函数但得到对象」;但直接传入InboxIcon组件本身则可正常运行,需要让第一种传递方式生效。
相关代码
index.tsx
import { Card } from '@/components/Card' import { InboxIcon } from '@/components/InboxIcon' const features = [ { title: 'hello', icon: <InboxIcon strokeWidth={6}/> }, ] export default function Home() { return ( <> {features.map((feature) => ( <Card key={feature.title} icon={feature.icon} /> ))} </> ) }
Card.tsx
interface Props { title: string icon: any } export function Card(props: Props) { return ( <div> <props.icon className="display-icon"/> {props.title} </div> ) }
InboxIcon.tsx
interface Props { className?: string strokeWidth: number } export function InboxIcon(props: Props) { return ( <svg className={props.className} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" aria-hidden="true" > <path strokeWidth={props.strokeWidth} fill="currentColor" d="M 70 110 C 70 140, 110 140, 110 110" /> </svg> ) }
错误原因
你在数组中存入的<InboxIcon strokeWidth={6}/>是已经通过React.createElement创建好的JSX元素对象,但在Card组件中却用<props.icon />的方式把它当作组件类/函数来调用——React渲染时会校验组件类型,期望传入的是可执行的组件,而非已渲染完成的元素对象,因此服务端抛出类型错误。
解决方案
方案一:直接渲染传入的JSX元素
修改Card.tsx,将组件调用语法改为直接渲染JSX元素的语法,同时如果需要给图标添加className,直接在数组中预渲染时传入:
修改后的index.tsx
const features = [ { title: 'hello', icon: <InboxIcon strokeWidth={6} className="display-icon"/> }, ]
修改后的Card.tsx
interface Props { title: string icon: React.ReactNode } export function Card(props: Props) { return ( <div> {props.icon} {props.title} </div> ) }
方案二:存储组件与props,动态渲染
如果需要在Card组件中动态给图标传递额外属性(比如统一添加className),可以在数组中存储组件本身和对应的props,而非预渲染的JSX元素:
修改后的index.tsx
const features = [ { title: 'hello', icon: InboxIcon, iconProps: { strokeWidth: 6 } }, ]
修改后的Card.tsx
import type { ElementType } from 'react'; interface Props { title: string icon: ElementType iconProps?: Record<string, unknown> } export function Card(props: Props) { const Icon = props.icon; return ( <div> <Icon {...props.iconProps} className="display-icon"/> {props.title} </div> ) }
内容的提问来源于stack exchange,提问作者user19666029
相关产品推荐
相关产品推荐

