【问题标题】:React.cloneElement / HOC / TransclusionReact.cloneElement / HOC / Transclusion
【发布时间】:2016-07-30 00:33:42
【问题描述】:

我正在用 React 组合一个表格控件,它几乎一直遵循这种模式,一直到单元格:

class Table extends Component {
    static propTypes = {
        tableClass: PropTypes.string,
        columnDefinitions: PropTypes.array.isRequired
    }

    constructor(props) {
        super(props);
    }

    render() {
        const { tableClass, children } = this.props;
        const passthroughProps = except(this.props, ['id', 'key', 'children', 'form', 'tableClass']);
        const transformedChildren = React.Children.map(children, c => React.cloneElement(c, passthroughProps));

        return (
            <div className={ `${ tableClass ? `${tableClass} ` : '' }table` }>
                { transformedChildren }
            </div>
        );
    }
}

export default Table;

except 只是一个实用程序,它可以获取对象的所有“自己的”属性除了第二个参数中定义的属性(作为属性名称数组)

在你告诉我使用高阶组件之前,让我提供更多细节。我以这种方式设计表格的原因是我希望人们能够使用如下所示的控件(他们可以提供自己的自定义实现)。

<Table columnDefinitions={columnDefinitions}>
    <Row>
        <Cell/>
        <Cell/>
        <Cell/>
    </Row>
    <CustomRow />
</Table>

即使我想放弃类似嵌入的方法 - 我不太确定如何使用高阶组件来执行此操作,因为它们似乎更适合用于更具确定性的方法。澄清一下,我们有一个用于 CardCardList 的 HOC:

const CardListHOC = (Card) => CardList extends Component {
    // propTypes, etc...
    render() {
        const { items } = this.props;
        const passthroughProps = except(this.props, ['id', 'key', 'children', 'form', 'items']);

        return (
            {items.map(i => (<div className="card-list-wrapper"><Card {...passthroughProps} item={i}/></div>)}
        );
    }
}

const CardHOC = (Child) => Card extends Component {
    // propTypes, etc...
    render() {
        const passthroughProps = except(this.props, ['id', 'key', 'children', 'form']);

        return (
            <div className="card-wrapper">
                <Child {...passthroughProps} />
            </div>
        );
    }
}

CardListHOC 只接受单一类型的Card,这意味着我传递给CardHOCChild 组件将必须为我的所有自定义类型的卡片实现所有自定义逻辑希望根据输入数据支持。

React.cloneElement 方法的问题在于,子元素首先呈现,因此在第一次通过时,子元素在“转换”之前没有来自其父级的道具 - 所以你最终会出现很多低效率和例如,我不能拥有 Row 组件,需要 columnDefinitions 作为道具,除非我像这样明确地将它们交给每个 Row

<Table columnDefinitions={columnDefinitions}>
    <Row columnDefinitions={columnDefinitions}>
        <Cell/>
        <Cell/>
        <Cell/>
    </Row columnDefinitions={columnDefinitions}>
    <CustomRow columnDefinitions={columnDefinitions}/>
</Table>

有没有更好的方法来解决这个问题?也许有一种我没有看到的 HOC 方法?如果有人能指出我正确的方向,将不胜感激!

【问题讨论】:

标签: javascript reactjs transclusion


【解决方案1】:

尽管可能令人惊讶——我不过是昨天——但 React Elements 并没有被 React.createElement(又名&lt;Element/&gt;)实例化。您可以尝试,仅当元素安装在 DOM 上时,该类才会被实例化。这就是为什么cloneElement 不是低效的原因,这就是为什么子元素在转换之前不会被渲染的原因。

话虽如此,您可能想看看 React context 以获得一些神奇的粉末。

【讨论】:

  • 嗯,我在所需的道具周围有一些奇怪的行为......我认为这与孩子在他们被转化之前被渲染有关,但也许是别的......是时候摆脱控制了大项目,孤立发展。
猜你喜欢
  • 1970-01-01
  • 2019-07-22
  • 2018-07-16
  • 1970-01-01
  • 1970-01-01
  • 2019-07-03
  • 2017-07-23
  • 2017-06-12
  • 2019-12-11
相关资源
最近更新 更多