<Parent>
<Child value="1">
<Child value="2">
</Parent>
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>);
}
});
用新道具克隆儿童
您可以使用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/
称呼孩子为功能
您也可以将道具传递给带有渲染道具的孩子。在这种方法中,子代(可以是children
或任何其他道具名称)是一个函数,可以接受您要传递的任何参数并返回子代:
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() {
return <div>{this.props.children(this.doSomething)}</div>
}
};
ReactDOM.render(
<Parent>
{doSomething => (
<React.Fragment>
<Child doSomething={doSomething} value="1" />
<Child doSomething={doSomething} value="2" />
</React.Fragment>
)}
</Parent>,
document.getElementById('container')
);
除了<React.Fragment>
或简单地<>
您还可以根据需要返回一个数组。
对于更简洁的方法,请尝试:
<div>
{React.cloneElement(this.props.children, { loggedIn: this.state.loggedIn })}
</div>
编辑:可以与多个单独的子项(子项本身必须是组件)一起使用。在 16.8.6 中测试
<div>
{React.cloneElement(props.children[0], { loggedIn: true, testingTwo: true })}
{React.cloneElement(props.children[1], { loggedIn: true, testProp: false })}
</div>
尝试这个
<div>{React.cloneElement(this.props.children, {...this.props})}</div>
它使用 react-15.1 为我工作。
查看所有其他答案
上下文旨在共享可被视为 React 组件树的 “全局” 数据,例如当前经过身份验证的用户,主题或首选语言。 1 个
免责声明:这是一个更新的答案,上一个使用了旧的上下文 API
它基于消费者 / 提供原则。首先,创建您的上下文
const { Provider, Consumer } = React.createContext(defaultValue);
然后通过
<Provider value={/* some value */}>
{children} /* potential consumers */
<Provider />
和
<Consumer>
{value => /* render something based on the context value */}
</Consumer>
只要提供商的价值支柱发生变化,作为提供商的后代的所有消费者都将重新渲染。 从 Provider 到其后代 Consumer 的传播不受 shouldComponentUpdate 方法的约束,因此即使上级组件退出了更新,也要对 Consumer 进行更新。 1 个
完整示例,半伪代码。
import React from 'react';
const { Provider, Consumer } = React.createContext({ color: 'white' });
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
value: { color: 'black' },
};
}
render() {
return (
<Provider value={this.state.value}>
<Toolbar />
</Provider>
);
}
}
class Toolbar extends React.Component {
render() {
return (
<div>
<p> Consumer can be arbitrary levels deep </p>
<Consumer>
{value => <p> The toolbar will be in color {value.color} </p>}
</Consumer>
</div>
);
}
}
随着React 16.6的更新,您现在可以使用React.createContext和contextType 。
import * as React from 'react';
// React.createContext accepts a defaultValue as the first param
const MyContext = React.createContext();
class Parent extends React.Component {
doSomething = (value) => {
// Do something here with value
};
render() {
return (
<MyContext.Provider value={{ doSomething: this.doSomething }}>
{this.props.children}
</MyContext.Provider>
);
}
}
class Child extends React.Component {
static contextType = MyContext;
onClick = () => {
this.context.doSomething(this.props.value);
};
render() {
return (
<div onClick={this.onClick}>{this.props.value}</div>
);
}
}
// Example of using Parent and Child
import * as React from 'react';
class SomeComponent extends React.Component {
render() {
return (
<Parent>
<Child value={1} />
<Child value={2} />
</Parent>
);
}
}
React.createContext在React.cloneElement案例无法处理嵌套组件的地方闪耀
class SomeComponent extends React.Component {
render() {
return (
<Parent>
<Child value={1} />
<SomeOtherComp><Child value={2} /></SomeOtherComp>
</Parent>
);
}
}
您可以使用React.cloneElement
,最好在开始在应用程序中使用它之前先了解它的工作方式。它是在React v0.13
引入的,请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 不同,此新函数没有合并样式和 className 的任何神奇的内置行为,其原因与我们在 transferPropsTo 中没有该功能的原因相同。没有人可以确定魔术物品的完整清单是什么,这使得很难推理代码,并且当样式具有不同的签名时(例如即将发布的 React Native),也很难重用。
React.cloneElement 几乎等同于:
<element.type {...element.props} {...props}>{children}</element.type>
但是,与 JSX 和 cloneWithProps 不同,它还保留引用。这意味着,如果您得到一个带有裁判的孩子,就不会意外地从祖先那里偷走它。您将获得与新元素相同的引用。
一种常见的模式是在孩子身上绘制地图并添加新道具。报告了很多有关 cloneWithProps 丢失引用的问题,这使得推理代码变得更加困难。现在,使用与 cloneElement 相同的模式将按预期工作。例如:
var newChildren = React.Children.map(this.props.children, function(child) {
return React.cloneElement(child, { foo: true })
});
注意:React.cloneElement(child,{ref:'newRef'})确实会覆盖 ref,因此,除非您使用 callback-refs,否则两个父对象仍然无法对同一个孩子进行 ref。
这是进入 React 0.13 的关键功能,因为道具现在是不可变的。升级路径通常是克隆元素,但是这样做可能会丢失引用。因此,我们需要一个更好的升级途径。在 Facebook 上升级呼叫站点时,我们意识到我们需要这种方法。我们从社区得到了同样的反馈。因此,我们决定在最终发行版之前再制作一个 RC,以确保我们能收到它。
我们计划最终弃用 React.addons.cloneWithProps。我们还没有这样做,但这是一个很好的机会,可以开始考虑您自己的用途并考虑使用 React.cloneElement。在实际删除发布版本之前,我们一定会先发布其中包含弃用通知的发布版本,因此无需立即采取措施。
这里更多...
允许您进行财产转移的最佳方法是让children
喜欢函数
例:
export const GrantParent = () => {
return (
<Parent>
{props => (
<ChildComponent {...props}>
Bla-bla-bla
</ChildComponent>
)}
</Parent>
)
}
export const Parent = ({ children }) => {
const somePropsHere = { //...any }
<>
{children(somePropsHere)}
</>
}
我需要修复上面接受的答案,以使其使用该答案而不是此指针。在 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
您不再需要{this.props.children}
。现在,您可以在Route
使用render
包装您的子组件,并像往常一样传递道具:
<BrowserRouter>
<div>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/posts">Posts</Link></li>
<li><Link to="/about">About</Link></li>
</ul>
<hr/>
<Route path="/" exact component={Home} />
<Route path="/posts" render={() => (
<Posts
value1={1}
value2={2}
data={this.state.data}
/>
)} />
<Route path="/about" component={About} />
</div>
</BrowserRouter>
考虑一个或多个孩子的更清洁方式
<div>
{ React.Children.map(this.props.children, child => React.cloneElement(child, {...this.props}))}
</div>