我试图找到正确的方法来定义一些组件,这些组件可以以通用的方式使用:

<Parent>
  <Child value="1">
  <Child value="2">
</Parent>

当然,在父组件和子组件之间呈现有一个逻辑,您可以想象<select>和<option>是这个逻辑的一个例子。

这是为了解决这个问题的一个虚拟实现:

var Parent = React.createClass({
  doSomething: function(value) {
  },
  render: function() {
    return (<div>{this.props.children}</div>);
  }
});

var Child = React.createClass({
  onClick: function() {
    this.props.doSomething(this.props.value); // doSomething is undefined
  },
  render: function() {
    return (<div onClick={this.onClick}></div>);
  }
});

问题是无论何时使用{this.props。Children}定义一个包装器组件,如何将某些属性传递给它的所有子组件?


当前回答

我在研究类似的需求时写了这篇文章,但我觉得克隆解决方案太受欢迎了,太原始了,把我的注意力从功能上转移开了。

我在react文档《高阶组件》中找到了一篇文章

以下是我的例子:

import React from 'react';

const withForm = (ViewComponent) => {
    return (props) => {

        const myParam = "Custom param";

        return (
            <>
                <div style={{border:"2px solid black", margin:"10px"}}>
                    <div>this is poc form</div>
                    <div>
                        <ViewComponent myParam={myParam} {...props}></ViewComponent>
                    </div>
                </div>
            </>
        )
    }
}

export default withForm;


const pocQuickView = (props) => {
    return (
        <div style={{border:"1px solid grey"}}>
            <div>this is poc quick view and it is meant to show when mouse hovers over a link</div>
        </div>
    )
}

export default withForm(pocQuickView);

对我来说,我在实现高阶组件的模式中找到了一个灵活的解决方案。

当然,这取决于功能,但如果其他人正在寻找类似的需求,这是很好的,这比依赖于原始级别的反应代码,如克隆要好得多。

我经常使用的另一种模式是容器模式。一定要读一读,那里有很多文章。

其他回答

没有一个答案解决了子组件不是React组件的问题,比如文本字符串。变通方法可以是这样的:

// Render method of Parent component
render(){
    let props = {
        setAlert : () => {alert("It works")}
    };
    let childrenWithProps = React.Children.map( this.props.children, function(child) {
        if (React.isValidElement(child)){
            return React.cloneElement(child, props);
        }
          return child;
      });
    return <div>{childrenWithProps}</div>

}

最巧妙的方法是:

    {React.cloneElement(this.props.children, this.props)}

也许您还可以发现这个特性很有用,尽管许多人认为这是一种反模式,但如果您知道自己在做什么并设计好解决方案,那么仍然可以使用它。

作为子组件的功能

根据cloneElement()的文档

React.cloneElement(
  element,
  [props],
  [...children]
)

克隆并返回一个新的React元素,使用element作为起始元素 点。生成的元素将具有原始元素的道具 新道具浅浅地融合在一起。新的孩子将取代 现有的儿童。原元素的Key和ref将为 保存了下来。 React.cloneElement()几乎等同于: <元素。{…元素类型。道具道具}{…}>{孩子}< / element.type > 然而,它也保留了裁判。这意味着如果你有了孩子 有裁判在上面,你就不会不小心从你的祖先那里偷了它。 你会得到相同的引用附加到你的新元素。

因此,您将使用cloneElement为儿童提供自定义道具。然而,组件中可能有多个子组件,您需要循环遍历它。其他答案建议你使用react。children。map来映射它们。然而React. children .map不同于React。cloneElement更改Element附加项和额外的。$作为前缀的键值。查看这个问题了解更多细节:React。React.Children.map中的cloneElement会导致元素键的改变

如果您希望避免它,您应该改用forEach函数,如

render() {
    const newElements = [];
    React.Children.forEach(this.props.children, 
              child => newElements.push(
                 React.cloneElement(
                   child, 
                   {...this.props, ...customProps}
                )
              )
    )
    return (
        <div>{newElements}</div>
    )

}

这是你所要求的吗?

var Parent = React.createClass({
  doSomething: function(value) {
  }
  render: function() {
    return  <div>
              <Child doSome={this.doSomething} />
            </div>
  }
})

var Child = React.createClass({
  onClick:function() {
    this.props.doSome(value); // doSomething is undefined
  },  
  render: function() {
    return  <div onClick={this.onClick}></div>
  }
})