web-dev-qa-db-fra.com

Comment utiliser les génériques dans les accessoires dans React dans un composant fonctionnel?

Dans un composant basé sur une classe, je peux facilement écrire du code comme celui-ci:

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'),
)

En fait, ce composant CollapsableDataList devrait être un composant fonctionnel car il est sans état, mais je ne sais pas comment écrire un composant fonction et utiliser des génériques dans les accessoires, un conseil pour moi?

6
hronro

Vous ne pouvez pas créer un composant fonctionnel avec une annotation de type et le rendre générique. Donc cela ne fonctionnera PAS car T n'est pas défini et vous ne pouvez pas le définir au niveau de la variable:

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

Vous pouvez cependant ignorer l'annotation de type, rendre la fonction générique et taper props explicitement.

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'),
)
13