如何在功能组件的 React 中使用 props 中的泛型?

新手上路,请多包涵

在基于类的组件中,我可以轻松编写如下代码:

 import * as React from 'react';
import { render } from 'react-dom';

interface IProps<T> {
    collapsed: boolean;
    listOfData: T[];
    displayData: (data: T, index: number) => React.ReactNode;
}

class CollapsableDataList<T> extends React.Component<IProps<T>> {
    render () {
        if (!this.props.collapsed) {
            return <span>total: {this.props.listOfData.length}</span>
        } else {
            return (
                <>
                    {
                        this.props.listOfData.map(this.props.displayData)
                    }
                </>
            )
        }
    }
}

render(
    <CollapsableDataList
        collapsed={false}
        listOfData={[{a: 1, b: 2}, {a: 3, b: 4}]}
        displayData={(data, index) => (<span key={index}>{data.a + data.b}</span>)}
    />,
    document.getElementById('root'),
)

实际上这个 CollapsableDataList 组件应该是一个函数组件,因为它是无状态的,但是我不知道如何编写一个函数组件并在道具中使用泛型,对我有什么建议吗?

原文由 hronro 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 764
2 个回答

您不能使用类型注释创建功能组件并使其通用。所以这将不起作用,因为 T 没有定义,你不能在变量级别定义它:

 const CollapsableDataList : React.FunctionComponent<IProps<T>> = p => { /*...*/ }

但是,您可以跳过类型注释,并使函数泛型并显式键入 props

 import * as React from 'react';
import { render } from 'react-dom';

interface IProps<T> {
    collapsed: boolean;
    listOfData: T[];
    displayData: (data: T, index: number) => React.ReactNode;
}
const CollapsableDataList = <T extends object>(props: IProps<T> & { children?: ReactNode }) => {
    if (!props.collapsed) {
        return <span>total: {props.listOfData.length}</span>
    } else {
        return (
            <>
                {
                    props.listOfData.map(props.displayData)
                }
            </>
        )
    }
}

render(
    <CollapsableDataList
        collapsed={false}
        listOfData={[{a: 1, b: 2}, {a: 3, c: 4}]}
        displayData={(data, index) => (<span key={index}>{data.a + (data.b || 0)}</span>)}
    />,
    document.getElementById('root'),
)

原文由 Titian Cernicova-Dragomir 发布,翻译遵循 CC BY-SA 4.0 许可协议

类型 React.FC 本质上是这样的:

 <P = {}>(props: PropsWithChildren<P>, context?: any) => ReactElement | null

所以而不是这个(这是不允许的):

 const Example: React.FC<Props<P>> = (props) => {
  // return a React element or null
}

你可以使用这个:

 const Example = <P extends unknown>(props: PropsWithChildren<Props<P>>): ReactElement | null => {
  // return a React element or null
}

例如:

 const Example = <P extends unknown>({ value }: PropsWithChildren<{ value: P }>): ReactElement | null => {
  return <pre>{JSON.stringify(value)}</pre>
}

或者,更严格地说,如果组件不使用 children 并且不会返回 null

 const Example = <P>({ value }: { value: P }): ReactElement => {
  return <pre>{value}</pre>
}

然后将键入的组件用作 <Example<string> value="foo"/>

原文由 Alf Eaton 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进