我试图找到正确的方法来定义一些可以以通用方式使用的组件:
<Parent> <Child value="1"> <Child value="2"> </Parent>
当然,在父组件和子组件之间进行渲染是有逻辑的,你可以想象<select>并<option>作为这个逻辑的一个例子。
<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}定义包装组件时,您如何将某些属性传递给它的所有子组件?
{this.props.children}
您可以使用React.Children迭代子元素,然后使用新的道具(浅合并)克隆每个元素React.cloneElement。例如:
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或任何其他道具名称)是一个可以接受您想要传递的任何参数并返回孩子的函数:
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>或简单地返回一个数组。<>
<React.Fragment>
<>