Динамическое имя компонента с реквизитами реагирует

#reactjs #typescript

Вопрос:

У меня есть PropertyCardList компонент, который принимает некоторые props . Я хочу передать только имя компонента от родителя, и список должен автоматически отображать его.

PropertyCardList.tsx

 import React from "react";
import { Grid, GridProps, GridSpacing } from "@material-ui/core";
import { NamedExoticComponent } from "react";
import { LargePropertyInfo, SmallPropertyInfo } from "../../@types/Property/Property";
import { SmallPropertyCardProps } from "../PropertyCards/SmallPropertyCard/SmallPropertyCard";
import { LargePropertyCardProps } from "../PropertyCards/LargePropertyCard/LargePropertyCard";

interface Props
{
    gridSpacing?: GridSpacing;
    gridItemProps?: GridProps;
    loading?: boolean;
    skeletonsCount?: number;
    properties: SmallPropertyInfo[] | LargePropertyInfo[];
    cardComponent: NamedExoticComponent <SmallPropertyCardProps> | NamedExoticComponent <LargePropertyCardProps>;
}

const PropertyCardList: React.FC <Props> = props =>
{
    if (props.loading)
    {
        return (
            <Grid container spacing={props.gridSpacing}>
                {new Array(props.skeletonsCount).fill(null).map((_, index) => (
                    <Grid
                        item
                        key={index}
                        {...props.gridItemProps}
                    >
                        <props.cardComponent
                            property={{}} // I have to typecast it using "as" but what should be the value?
                            loading={true}
                        />
                    </Grid>
                ))}
            </Grid>
        )
    }

    return (
        <Grid container spacing={props.gridSpacing}>
            {props.properties.map((property) => (
                <Grid
                    item
                    key={property.id}
                    {...props.gridItemProps}
                >
                    <props.cardComponent
                        property={property} // I get error here saying that subType, ownership missing in SmallPropertyInfo. It makes sense but this needs to be dynamic as well
                    />
                </Grid>
            ))}
        </Grid>
    );
}

PropertyCardList.defaultProps = {
    skeletonsCount: 3,
}

export default React.memo(PropertyCardList);

 

Интерфейсы

 export interface PropertyBase
{
    id: string;
    images: string[];
    beds: number;
    baths: number;
    areaSize: number;
    price: PropertyPrice;
    address: ObjectWithTranslation;
}

export interface SmallPropertyInfo extends PropertyBase
{
    purpose: PropertyPurpose;
}

export interface LargePropertyInfo extends SmallPropertyInfo
{
    subType: PropertySubType;
    ownership: PropertyOwnership;
    installment: Omit <PropertyPrice, "type">;
}

 

Ниже показано, как я использую компонент списка:

 <PropertyCardList
    cardComponent={isMobile ? SmallPropertyCard : LargePropertyCard}
    properties={properties.data}
    gridSpacing={2}
    gridItemProps={{
        lg: 6,
        xs: 12
    }}
    loading={loading}
    skeletonsCount={5}
/>
 

Является ли это правильным подходом к созданию общего компонента списка или мне следует создавать отдельные компоненты списка для каждого отдельного типа? (Это будет дублировать много кода)

Ответ №1:

В react можно использовать условную визуализацию, и действительно полезно удалить избыточную реализацию кодирования.

Вы можете использовать его в качестве переменной в теле функции следующим образом.

 const cardComponent= isMobile ? SmallPropertyCard : LargePropertyCard
 

А затем используйте его для перехода в дочерний компонент следующим образом.

 <PropertyCardList
    cardComponent={cardComponent}
    properties={properties.data}
    gridSpacing={2}
    gridItemProps={{
        lg: 6,
        xs: 12
    }}
    loading={loading}
    skeletonsCount={5}
/>
 

То, как вы его используете, тоже правильно.

Комментарии:

1. Моя ошибка связана с PropertyCardList компонентом из-за конфликтов типов (я написал комментарий). То, о чем вы упомянули, уже работает нормально.