Как использовать дженерики в реквизитах в React в функциональном компоненте? - PullRequest
0 голосов
/ 28 декабря 2018

В компоненте на основе классов я могу легко написать некоторый код, подобный следующему:

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 компонент должен быть функциональным компонентом, поскольку он не имеет состояния, но я не могу понять, какнаписать компонент функции и использовать дженерики в реквизите, какой-нибудь совет для меня?

1 Ответ

0 голосов
/ 28 декабря 2018

Вы не можете создать функциональный компонент с аннотацией типа и сделать его универсальным.Так что это НЕ будет работать, так как 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'),
)
...