我试图找到正确的方法来定义一些组件,这些组件可以以通用的方式使用:
<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}定义一个包装器组件,如何将某些属性传递给它的所有子组件?
从上面所有的答案中得到启发,这就是我所做的。我传递一些道具,比如一些数据和一些组件。
import React from "react";
const Parent = ({ children }) => {
const { setCheckoutData } = actions.shop;
const { Input, FieldError } = libraries.theme.components.forms;
const onSubmit = (data) => {
setCheckoutData(data);
};
const childrenWithProps = React.Children.map(
children,
(child) =>
React.cloneElement(child, {
Input: Input,
FieldError: FieldError,
onSubmit: onSubmit,
})
);
return <>{childrenWithProps}</>;
};
用新道具克隆孩子
你可以使用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 >
你可以使用React。在开始在应用程序中使用它之前,最好了解它的工作方式。它是在React v0.13中引入的,请继续阅读以获取更多信息,因此您将了解到以下内容:
<div>{React.cloneElement(this.props.children, {...this.props})}</div>
所以,请从React文档中找到这些行,让你了解它是如何工作的,以及如何使用它们:
在React v0.13 RC2中,我们将引入一个新的API,类似于
React.addons。cloneWithProps,用这个签名:
React.cloneElement(element, props, ...children);
与cloneWithProps不同,这个新函数没有任何魔力
出于同样的原因合并style和className的内置行为
我们在transferPropsTo中没有这个特性。没人能确定
所有魔法物品都是这样,所以
很难推理的代码和重用时的风格
有一个不同的签名(例如在即将到来的React Native中)。
反应。cloneElement几乎等同于:
<element.type {...element.props} {...props}>{children}</element.type>
然而,与JSX和cloneWithProps不同,它还保留了引用。这
意味着如果你得到一个有裁判的子球,你不会不小心
从你祖先那里偷来。你会得到相同的引用
你的新元素。
一种常见的模式是映射子元素并添加一个新道具。
有许多关于cloneWithProps失去ref的问题报道,
让你的代码更难推理。同样的道理
使用cloneElement的pattern将按预期工作。例如:
var newChildren = React.Children.map(this.props.children, function(child) {
return React.cloneElement(child, { foo: true })
});
注意:反应。cloneElement(child, {ref: 'newRef'})会覆盖
所以这仍然是不可能的两个父母有一个裁判
相同的子元素,除非你使用callback-refs。
这是React 0.13的一个关键功能,因为现在有道具了
不可变的。升级路径通常是克隆元素,但通过
这样做你可能会失去裁判。因此,我们需要一个更好的升级
路径。当我们升级Facebook的呼叫网站时,我们意识到这一点
我们需要这个方法。我们从社区得到了同样的反馈。
因此我们决定在最终版本之前再做一个RC
一定要把这个弄进去。
我们计划最终弃用React.addons.cloneWithProps。我们不是
还在做,但这是一个开始思考的好机会
你可以考虑使用React。cloneElement代替。我们会
确保在我们真正发布之前发布一个带有弃用通知的版本
删除它,这样就不需要立即采取行动。
这里……
我需要修复上面接受的答案,以使它使用该指针而不是这个指针。在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