React.cloneElement / HOC / Transclusion

时间:2016-04-08 16:33:47

标签: javascript reactjs transclusion

我将一个表格控件与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只是一个实用程序,可以抓取所有对象&#34;拥有&#34;属性除了,用于第二个参数中定义的属性(作为属性名称数组)

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

<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,这意味着我传递给Child的{​​{1}}组件必须实现所有自定义逻辑对于我想根据输入数据支持的所有自定义类型的卡。

CardHOC方法的问题在于,首先渲染子元素,因此在第一次传递时,子元素不会从父母那里获得道具,直到它们被转换为#34; - 所以你最终会遇到很多效率低下的问题而且我不能拥有React.cloneElement组件,例如,需要Row作为道具,除非我明确地将它们交给每个columnDefinitions像这样:

Row

有没有更好的方法来解决这个问题?也许我和HOC没有相似之处?如果有人能指出我正确的方向,那将非常感激!

1 个答案:

答案 0 :(得分:1)

尽管它可能是令人惊讶的 - 我只是昨天 - 但React Elements并未与React.createElement(又名<Element/>)进行实例化。您可以尝试,只有在元素安装在DOM上时才会对类进行实例化。这就是cloneElement效率不高的原因,这就是为什么子元素在变换之前不会被渲染的原因。

话虽如此,你可能想看看React context是否有一些神奇的粉末。