TypeScript无法将组件作为属性传递

5rgfhyps  于 2023-03-31  发布在  TypeScript
关注(0)|答案(1)|浏览(125)

我正在使用Next.js和TypeScript。我有一个项目数组,我循环并显示在我的HTML中。当我在我的项目数组中传递名为“InboxIcon”的组件作为JSX时,我得到了下面的错误:
这不起作用...它导致错误

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

服务器错误错误元素类型无效:应为字符串(对于内置组件)或类/函数(对于复合组件),但得到:对象。
生成页面时发生此错误。任何控制台日志都将显示在终端窗口中。调用堆栈renderElement
This works

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

我怎样才能让第一种方法起作用呢?

索引.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}                                        
                />
            ))}
        </>
)

卡片.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>
    )
}
z2acfund

z2acfund1#

在功能组件方面,这一行:

<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"})

因此,错误:“元素无效...得到:对象”。
希望你能明白为什么这行不通。
幸运的是,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>

相关问题