如何将道具传递给{this.props.children}
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何将道具传递给{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}
定义包装器组件,如何将一些属性传递给它的所有子组件?
您可以使用React.Children迭代子项,然后使用React.cloneElement克隆每个元素使用新的道具(浅合并),例如:
const Child = ({ doSomething, value }) => (
<div onClick={() => doSomething(value)}>Click Me</div>
);
class Parent extends React.PureComponent {
doSomething = (value) => {
console.log('doSomething called by child with value:', value);
}
render() {
const childrenWithProps = React.Children.map(this.props.children, child =>
React.cloneElement(child, { doSomething: this.doSomething })
);
return <div>{childrenWithProps}</div>
}
};
ReactDOM.render(
<Parent>
<Child value="1" />
<Child value="2" />
</Parent>,
document.getElementById('container')
);
小提琴:https://jsfiddle.net/2q294y43/2/
您还可以使用render props将道具传递给儿童。
考虑一个或多个孩子的清洁方式
<div>
{ React.Children.map(this.props.children, child => React.cloneElement(child, {...this.props}))}
</div>
这些答案都没有解决让孩子成为非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>
}
Parent.jsx:
import React from 'react';
const doSomething = value => {};
const Parent = props => (
<div>
{
!props || !props.children
? <div>Loading... (required at least one child)</div>
: !props.children.length
? <props.children.type {...props.children.props} doSomething={doSomething} {...props}>{props.children}</props.children.type>
: props.children.map((child, key) =>
React.cloneElement(child, {...props, key, doSomething}))
}
</div>
);
Child.jsx:
import React from 'react';
/* but better import doSomething right here,
or use some flux store (for example redux library) */
export default ({ doSomething, value }) => (
<div onClick={() => doSomething(value)}/>
);
和main.jsx:
import React from 'react';
import { render } from 'react-dom';
import Parent from './Parent';
import Child from './Child';
render(
<Parent>
<Child/>
<Child value='1'/>
<Child value='2'/>
</Parent>,
document.getElementById('...')
);
看这里的例子:https://plnkr.co/edit/jJHQECrKRrtKlKYRpIWl?p=preview
根据cloneElement()
的文件
React.cloneElement(
element,
[props],
[...children]
)
使用element作为起点克隆并返回一个新的React元素。结果元素将具有原始元素的道具,新道具以浅层方式合并。新的孩子将取代现有的孩子。 key和ref将保留原始元素。
React.cloneElement()
几乎相当于:<element.type {...element.props} {...props}>{children}</element.type>
但是,它也保留了refs。这意味着,如果你的孩子有一个参考,你不会意外地从你的祖先窃取它。您将获得与新元素相同的参考。
因此,cloneElement将用于为子项提供自定义道具。但是,组件中可能有多个子项,您需要循环它。其他答案建议您使用React.Children.map
映射它们。然而,与React.Children.map
不同的React.cloneElement
更改了Element附加的键和额外的.$
作为前缀。查看此问题以获取更多详细信息:React.cloneElement inside React.Children.map is causing element keys to change
如果你想避免它,你应该去像forEach
函数
render() {
const newElements = [];
React.Children.forEach(this.props.children,
child => newElements.push(
React.cloneElement(
child,
{...this.props, ...customProps}
)
)
)
return (
<div>{newElements}</div>
)
}
也许你也可以找到有用的这个功能,虽然很多人都认为这是一种反模式,如果你知道自己在做什么并设计好你的解决方案,它仍然可以使用。
如果你有多个孩子想要pass props,你可以这样做,使用React.Children.map:
render() {
let updatedChildren = React.Children.map(this.props.children,
(child) => {
return React.cloneElement(child, { newProp: newProp });
});
return (
<div>
{ updatedChildren }
</div>
);
}
如果你的组件只有一个孩子,则不需要映射,你可以立即克隆元素:
render() {
return (
<div>
{
React.cloneElement(this.props.children, {
newProp: newProp
})
}
</div>
);
}
最简洁的方法:
{React.cloneElement(this.props.children, this.props)}
继@and_rest回答之后,这就是我克隆孩子并添加一个类的方法。
<div className="parent">
{React.Children.map(this.props.children, child => React.cloneElement(child, {className:'child'}))}
</div>
对于任何一个拥有单个子元素的人来说,这应该是这样做的。
{React.isValidElement(this.props.children)
? React.cloneElement(this.props.children, {
...prop_you_want_to_pass
})
: null}
我认为渲染道具是处理这种情况的适当方式
您让Parent提供子组件中使用的必要道具,通过重构Parent代码来查找如下所示:
const Parent = ({children}) => {
const doSomething(value) => {}
return children({ doSomething })
}
然后在子组件中,您可以通过以下方式访问父级提供的功能:
class Child extends React {
onClick() => { this.props.doSomething }
render() {
return (<div onClick={this.onClick}></div>);
}
}
现在最终的结构将如下所示:
<Parent>
{(doSomething) =>
(<Fragment>
<Child value="1" doSomething={doSomething}>
<Child value="2" doSomething={doSomething}>
<Fragment />
)}
</Parent>
要获得更简洁的方法,请尝试:
<div>
{React.cloneElement(this.props.children, { loggedIn: this.state.loggedIn })}
</div>
注意:这只有在有一个子节点时才有效,并且它是一个有效的React元素。
Method 1 - clone children
const Parent = (props) => { const attributeToAddOrReplace= "Some Value" const childrenWithAdjustedProps = React.Children.map(props.children, child => React.cloneElement(child, { attributeToAddOrReplace}) ); return <div>{childrenWithAdjustedProps }</div> }
以上是关于如何将道具传递给{this.props.children}的主要内容,如果未能解决你的问题,请参考以下文章