如何将道具传递给 {this.props.children}

新手上路,请多包涵

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

<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} 定义包装组件时,如何将某些属性传递给它的所有子组件?

原文由 plus- 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 636
2 个回答

用新道具克隆孩子

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

 const Child = ({ doSomething, value }) => (
 <button onClick={() => doSomething(value)}>Click Me</button>
 );

 function Parent({ children }) {
 function doSomething(value) {
 console.log("doSomething called by child with value:", value);
 }

 const childrenWithProps = React.Children.map(children, child => {
 // Checking isValidElement is the safe way and avoids a typescript
 // error too.
 if (React.isValidElement(child)) {
 return React.cloneElement(child, { doSomething });
 }
 return child;
 });

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

 function App() {
 return (
 <Parent>
 <Child value={1} />
 <Child value={2} />
 </Parent>
 );
 }

 ReactDOM.render(<App />, document.getElementById("container"));
 <script src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
 <script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
 <div id="container"></div>

将孩子作为函数调用

或者,您可以使用 render props 将 props 传递给孩子。在这种方法中,孩子(可以是 children 或任何其他道具名称)是一个可以接受您想要传递的任何参数并返回孩子的函数:

 const Child = ({ doSomething, value }) => (
 <button onClick={() => doSomething(value)}>Click Me</button>
 );

 function Parent({ children }) {
 function doSomething(value) {
 console.log("doSomething called by child with value:", value);
 }

 // Note that children is called as a function and we can pass args to it.
 return <div>{children(doSomething)}</div>
 }

 function App() {
 // doSomething is the arg we passed in Parent, which
 // we now pass through to Child.
 return (
 <Parent>
 {doSomething => (
 <React.Fragment>
 <Child doSomething={doSomething} value={1} />
 <Child doSomething={doSomething} value={2} />
 </React.Fragment>
 )}
 </Parent>
 );
 }

 ReactDOM.render(<App />, document.getElementById("container"));
 <script src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
 <script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
 <div id="container"></div>

如果您愿意,也可以返回一个数组,而不是 <React.Fragment> 或简单的 <>

原文由 Dominic 发布,翻译遵循 CC BY-SA 4.0 许可协议

要获得更简洁的方法,请尝试:

 <div>
    {React.cloneElement(this.props.children, { loggedIn: this.state.loggedIn })}
</div>

编辑:要与多个单独的孩子一起使用(孩子本身必须是一个组件),您可以这样做。在 16.8.6 中测试

<div>
    {React.cloneElement(this.props.children[0], { loggedIn: true, testPropB: true })}
    {React.cloneElement(this.props.children[1], { loggedIn: true, testPropA: false })}
</div>

原文由 Andres F Garcia 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题