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

<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文档《高阶组件》中找到了一篇文章

以下是我的例子:

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>

}

这是你所要求的吗?

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>
  }
})

用新道具克隆孩子

你可以使用React。子元素遍历子元素,然后使用React.cloneElement用新道具(浅合并)克隆每个元素。

请参阅代码注释,为什么我不推荐这种方法。

const Child = ({childName, sayHello}) => ( <button onClick={() => sayHello(childName)}>{childName}</button> ); 函数父({children}) { //我们将sayHello函数传递给子元素。 函数sayHello(childName) { console.log(' Hello from ${childName} the child '); } const childrenWithProps = React.Children。映射(children, child => { //检查isValidElement是安全的方法,可以避免 // typescript错误。 if (React.isValidElement(child)) { 返回的反应。cloneElement(child, {sayHello}); } 返回的孩子; }); 返回< div > {childrenWithProps} < / div > } 函数App() { //这种方法不太类型安全,Typescript不友好 //看起来像你试图渲染' Child '没有' sayHello '。 //这也会让代码的读者感到困惑。 回报( <父> <Child childName="Billy" /> <Child childName="Bob" /> 父> < / ); } ReactDOM。render(<App />, document.getElementById("container")); < script src = " https://unpkg.com/react@17 umd格式/ react.production.min.js " > < /脚本> < script src = " https://unpkg.com/react-dom@17 umd格式/ react-dom.production.min.js " > < /脚本> < div id = "容器" > < / div >

将子函数作为函数调用

或者,你可以通过渲染道具将道具传递给孩子们。在这种方法中,children(可以是children或任何其他道具名)是一个函数,它可以接受你想传递的任何参数,并返回实际的子函数:

const Child = ({childName, sayHello}) => ( <button onClick={() => sayHello(childName)}>{childName}</button> ); 函数父({children}) { 函数sayHello(childName) { console.log(' Hello from ${childName} the child '); } //这个组件的children必须是一个函数 //返回实际的子节点。我们可以通过 //它的参数然后传递给他们作为道具(在这个 //如果我们传递' sayHello ')。 返回< div >{孩子(sayHello)} < / div > } 函数App() { // sayHello是我们在Parent中传递的参数 //我们现在传递到Child。 回报( <父> {(sayHello) => ( <反应。片段> <Child childName="Billy" sayHello={sayHello} /> <Child childName="Bob" sayHello={sayHello} /> < /反应。片段> )} 父> < / ); } ReactDOM。render(<App />, document.getElementById("container")); < script src = " https://unpkg.com/react@17 umd格式/ react.production.min.js " > < /脚本> < script src = " https://unpkg.com/react-dom@17 umd格式/ react-dom.production.min.js " > < /脚本> < div id = "容器" > < / div >

我需要修复上面接受的答案,以使它使用该指针而不是这个指针。在map函数的范围内没有定义doSomething函数。

var Parent = React.createClass({
doSomething: function() {
    console.log('doSomething!');
},

render: function() {
    var that = this;
    var childrenWithProps = React.Children.map(this.props.children, function(child) {
        return React.cloneElement(child, { doSomething: that.doSomething });
    });

    return <div>{childrenWithProps}</div>
}})

更新:此修复适用于ECMAScript 5,在ES6中不需要var that=this