来自配置的 React 和 Typescript 动态组件

Posted

技术标签:

【中文标题】来自配置的 React 和 Typescript 动态组件【英文标题】:React and Typescript dynamic component from config 【发布时间】:2021-08-13 05:28:50 【问题描述】:

我正在尝试使用 reactjs 和 typescript 构建一个动态菜单系统。

我的配置如下所示:

import TableIcon from "@heroicons/react/solid";

type route = 
    icon: React.ReactNode,
    path: string,
    title: string,


export const navRoutes = () : route[] => 
    return [
        
            icon: TableIcon,
            path: '/',
            title: 'Home'
        ,
    ]

在我的导航组件中,我正在做

navRoutes().map((item) => (
    <a key=item.title href=item.path>
        <item.icon /> // also tried item.icon
        item.title
    </a>
))

我收到一个错误,TS2604: JSX element type 'item.icon' does not have any construct or call signatures.

我在没有按预期工作的打字稿的情况下做了类似的事情——谁能告诉我我做错了什么?

【问题讨论】:

【参考方案1】:

React.ReactNode 是渲染组件的类型。例如:

const a: React.ReactNode = <TableIcon />

如果你想传入一些渲染 JSX,那就是你会使用的。但听起来你想传入一个没有道具的功能组件,然后然后被渲染。

React.FC 是没有道具的反应功能组件的通用类型。这可能就是你想要的类型。

type route = 
    icon: React.FC,
    path: string,
    title: string,

Playground

【讨论】:

【参考方案2】:

React.ReactNode 类型描述了调用 JSX 组件而不是组件本身的返回值。您可以:

1 ) 传递一个React.ReactNode:

type route = 
  icon: React.ReactNode;
  path: string;
  title: string;
;

export const navRoutes = (): route[] => 
  return [
    
      icon: <TableIcon />,
      path: "/",
      title: "Home"
    
  ];
;

navRoutes().map((item) => (
  <a key=item.title href=item.path>
    item.icon
    item.title
  </a>
))
    传递一个可调用的组件。通常你需要给它一个大写的名字以便通过 JSX 调用它。不知何故&lt;item.icon/&gt; 似乎有效?但为了安全起见,我会大写。
type route = 
  icon: React.ComponentType;
  path: string;
  title: string;
;

export const navRoutes = (): route[] => 
  return [
    
      icon: TableIcon,
      path: "/",
      title: "Home"
    
  ];
;

navRoutes().map((title, path, icon: Icon) => (
  <a key=title href=path>
    <Icon/>
    title
  </a>
))

默认情况下React.ComponentType 不使用任何道具(除了孩子)。如果您想在调用&lt;Icon/&gt; 时传递道具,可以使用React.ComponentType&lt;SomePropsType&gt;

【讨论】:

【参考方案3】:

您可以使用 JSX.Element 代替 React.ReactNode,这就是 @heroicons/react 作为类型返回的内容

页脚社交图标(为本示例添加了 TableIcon)

import  FC  from 'react';
import cn from 'classnames';
import 
    Facebook,
    Instagram,
    SquareLogo
 from '@/components/UI/Icons';
import  TableIcon  from '@heroicons/react/solid';
import css from './footer.module.css';

export interface FooterSocialProps 
    href: string;
    label: string;
    id: number;
    icon: JSX.Element;


export const footerSocial: FooterSocialProps[] = [
    
        href: 'https://www.facebook.com/thefaderoominc/?ref=py_c',
        label: 'Facebook',
        id: 0,
        icon: <Facebook />
    ,
    
        href: 'https://www.instagram.com/thefaderoomhighlandpark/',
        label: 'Instagram',
        id: 1,
        icon: <Instagram />
    ,
    
        href: 'https://squareup.com/gift/MLHZCDVC0MKB1/order',
        label: 'Square Giftcards',
        id: 2,
        icon: <SquareLogo />
    ,
    
        href: 'https://***.com/example',
        label: 'Table Icon',
        id: 3,
        icon: <TableIcon />
    
];

export interface FooterSocialPropsFC 
    className?: string;


const FooterSocial: FC<FooterSocialPropsFC> = (
    className
) => 
    return (
        <div className=cn(css.socialRoot, className)>
            footerSocial.map((social, i) => (
                <div key=++i>
                    <a
                        title=social.label
                        target='__blank'
                        href=social.href
                        className=cn(
                            css.socialLink,
                            'text-olive-300 hover:text-olive-400  text-opacity-80'
                        )
                    >
                        <span className='sr-only'>
                            `External Link to The Fade Room's $social.label page`
                        </span>
                        social.icon
                    </a>
                </div>
            ))
        </div>
    );
;

export default FooterSocial;

【讨论】:

以上是关于来自配置的 React 和 Typescript 动态组件的主要内容,如果未能解决你的问题,请参考以下文章

使来自 react-intl 的 FormattedMessage 中的 id 继承自自定义 TypeScript 接口以启用 VS IntelliSense 和类型检查

React with TypeScript 系列 --概述

使用来自使用旧版 Typescript 确定类型的 Typescript 定义文件

使用 airbnb 和 prettier 扩展的 ESLint 配置,用于使用 typescript、jest 和 react-hooks 的 react 项目

在React中配置typescript

深入浅出TypeScript- 在React项目中使用TypeScript