TypeScript不能将component作为prop传递



我在TypeScript中使用Next.js。我有一个项目数组,我循环遍历并显示在HTML中。当我传入名为"InboxIcon"的组件时,我得到了下面的错误如JSX在我的数组项目,如:

❌这不起作用…它导致错误

const features = [
{        
title: 'hello'
icon: <InboxIcon strokeWidth={6}/>        
},
]

服务器错误错误:元素类型无效:期望一个字符串(for内置组件)或类/函数(用于组合组件)但得到:object

生成页面时发生错误。任何控制台日志都将显示在终端窗口中。调用Stack renderElement

✅This works

const features = [
{        
title: 'hello'
icon: InboxIcon
},
]

我怎样才能使第一种方法工作呢?

index.tsx

import { ItemColumnOne } 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

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}/>

等价于:

InboxIcon({strokeWidth: 6});

和这一行:

<props.icon className="display-icon"/>

等价于:

props.icon({className: "display-icon"})

最基本的形式是这样的:

// This returns a component, which is an object
const icon = InboxIcon({strokeWidth: 6}); 
// You're trying to call an object like a function
icon({className: "display-icon"}) 

因此出现错误:"Element is invalid…有:object" .

希望你能明白为什么这不起作用。


幸运的是,React提供了一种方便的方式来为现有组件添加属性:cloneElement

export function Card(props: Props) {
return (
<div>
{cloneElement(props.icon, {className: "display-icon"})}                                                                                                                                  
{props.title}
</div>
)
}
const features = [
{        
title: 'hello'
icon: <InboxIcon strokeWidth={6}/>        
},
]

Stackblitz Typescript示例:

https://stackblitz.com/edit/react-ts-6ufs9e?file=index.tsx


JavaScript代码片段示例

const rootElement = document.getElementById('root');
const root = ReactDOM.createRoot(rootElement);
root.render(<Home />);
const features = [
{
title: 'hello',
icon: <InboxIcon strokeWidth={6} />,
},
];
function Home() {
return (
<div>
{features.map((feature) => (
<Card key={feature.title} title={feature.title} icon={feature.icon} />
))}
</div>
);
}
function Card(props) {
return (
<div>
{React.cloneElement(props.icon, { className: 'display-icon' })}
{props.title}
</div>
);
}
function InboxIcon(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>
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
<div id='root'></div>

最新更新