You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React实现带Props动态组件渲染,PropertyCardList通用化方案咨询

你的通用列表组件设计思路完全正确,完全不需要为每种卡片单独编写列表组件,重复代码不仅冗余,后续迭代修改布局、加载逻辑时还要同步改多份,维护成本极高。你当前遇到的类型报错,本质是没有用泛型把「传入的卡片组件类型」和「properties数组的类型」做关联,TS无法识别两者的对应关系,才会报字段缺失的错误。

修复方案

把PropertyCardList改造成泛型组件,用泛型约束绑定卡片props和数据类型即可:

1. 改写组件类型定义

import React from "react";
import { Grid, GridProps, GridSpacing } from "@material-ui/core";
import { PropertyBase } from "../../@types/Property/Property";

// 泛型T约束为继承PropertyBase的类型,自动适配不同的property结构
interface Props<T extends PropertyBase> {
    gridSpacing?: GridSpacing;
    gridItemProps?: GridProps;
    loading?: boolean;
    skeletonsCount?: number;
    properties: T[];
    // 卡片组件的props和泛型T绑定,确保类型对应
    cardComponent: React.ComponentType<{ property: T; loading: boolean }>;
}

const PropertyCardList = <T extends PropertyBase>(props: Props<T>) => {
    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
                            // loading状态下property不会被实际使用,直接断言为T即可
                            property={{} as T}
                            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}
                        loading={false}
                    />
                </Grid>
            ))}
        </Grid>
    );
}

PropertyCardList.defaultProps = {
    skeletonsCount: 3,
}

// 这里要加一层类型断言,避免React.memo抹掉泛型信息
export default React.memo(PropertyCardList) as typeof PropertyCardList;

2. 原有调用逻辑无需修改

你现在的组件调用代码可以完全不变,TS会自动根据你传入的cardComponent和properties匹配对应的泛型类型,不会再报字段缺失的错误。

方案说明

你原来的写法里把properties和cardComponent都定义成了独立的联合类型,TS没法判断你传入的SmallPropertyCard对应的就是SmallPropertyInfo数组,只会认为存在「用LargePropertyCard接收SmallPropertyInfo」的可能性,所以会提示缺少字段。用泛型绑定两个属性的类型之后,两者就形成了关联关系,TS可以做准确的类型推断。

这种设计是非常典型的容器组件实现方式,列表只负责通用的网格布局、加载态骨架屏渲染逻辑,卡片渲染完全交给上层自定义,符合单一职责原则,后续新增卡片类型也不需要修改列表组件的代码,复用性和可扩展性都很好。


内容的提问来源于stack exchange,提问作者Zahid Saeed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 05:21:01