在React.js中,没有一种简单的方法可以使用事件将子项的 props
传递给它的父项吗?
var Child = React.createClass({
render: function() {
<a onClick={this.props.onClick}>Click me</a>
}
});
var Parent = React.createClass({
onClick: function(event) {
// event.component.props ?why is this not available?
},
render: function() {
<Child onClick={this.onClick} />
}
});
我知道你可以使用受控组件来传递输入的值,但是传递整个工具包n'kaboodle会很好 . 有时,子组件包含一组您不必查找的信息 .
也许有一种方法将组件绑定到事件?
更新 - 2015年9月1日
在使用React超过一年之后,在Sebastien Lorber的推动下,通过传递子组件作为父母功能的参数实际上并不是React方式,也不是一个好主意 . 我已经改变了答案 .
6 回答
问题是如何将参数从子组件传递到父组件 . 这个例子易于使用和测试:
Look at JSFIDDLE
看来有一个简单的答案 . 考虑一下:
关键是在
this.props.onClick
事件上调用bind(null, this)
,从父项传递 . 现在,onClick函数接受参数component
,ANDevent
. 我认为这是世界上最好的 .更新:2015年9月1日
这是一个坏主意:让子实现细节泄露给父母从来都不是一条好路 . 见Sebastien Lorber的回答 .
Basically you use props to send information to and from Child and Parent.
添加所有精彩答案,让我举一个简单的例子来解释在React中从子组件传递值到父组件
App.js
Header.js
Main.js
多数民众赞成,现在您可以将值从客户端传递到服务器 .
看一下Header.js中的Change函数
这就是你如何将值从客户端推送到服务器的道具
这是在父构造函数中使用函数绑定的简单3步ES6实现 . 这是官方反应教程推荐的第一种方式(此处还没有涉及公共类字段语法) . 你可以在这里找到所有这些信息https://reactjs.org/docs/handling-events.html
绑定父函数,以便孩子可以调用它们(并将数据传递给父母!:D)
确保在父构造函数中绑定在父级中创建的函数
将绑定函数作为prop传递给子节点(No lambda,因为我们将ref传递给函数)
从子事件中调用绑定函数(Lambda!我们're calling the function when the event is fired. If we don' t这样做,该函数将在加载时自动运行,而不会在事件上触发 . )
父功能
父构造函数
通过儿童的道具
儿童活动电话
更新(2015年1月9日):OP使这个问题成为一个移动目标 . 它已经再次更新 . 所以,我觉得有责任更新我的回复 .
首先,回答您提供的示例:
是的,这是可能的 .
您可以通过将Child的
onClick
更新为this.props.onClick.bind(null, this)
来解决此问题:然后,Parent中的事件处理程序可以访问组件和事件,如下所示:
JSBin snapshot
但问题本身就是误导
Parent already knows Child’s props.
这在提供的示例中不清楚,因为实际上没有提供道具 . 此示例代码可能更好地支持所询问的问题:
It becomes much clearer in this example that you already know what the props of Child are.
JSBin snapshot
如果它真的是关于使用儿童道具......
如果它真的是关于使用Child的道具,你可以完全避免与Child的任何连接 .
JSX有一个spread attributes API我经常在像Child这样的组件上使用 . 它需要所有
props
并将它们应用于组件 . 孩子看起来像这样:允许您直接在Parent中使用这些值:
JSBin snapshot
And there's no additional configuration required as you hookup additional Child components
JSBin snapshot
但我怀疑这不是你的实际用例 . 那么让我们进一步挖掘......
一个强有力的实际例子
所提供示例的一般性质很难谈 . 我创建了一个组件,演示了上述问题的实际用途,以一种非常复杂的方式实现:
DTServiceCalculator working example
DTServiceCalculator repo
该组件是一个简单的服务计算器 . 您向它提供服务列表(包含名称和价格),它将计算所选价格的总和 .
孩子们幸福无知
ServiceItem是此示例中的子组件 . 它对外界没有太多意见 . 它requires a few props,其中一个是单击时要调用的函数 .
<div onClick={this.props.handleClick.bind(this.props.index)} />
它只会使用提供的
index
[source]调用提供的handleClick
回调 .父母是孩子
DTServicesCalculator是父组件就是这个例子 . 它也是一个孩子 . 我们看看吧 .
DTServiceCalculator
创建一个子组件列表(ServiceItem
s)并为其提供道具[source] . 它是ServiceItem
的父组件,但它是将组件传递给列表的组件的子组件 . 它不拥有数据 . 所以它再次将组件的处理委托给其父组件source<ServiceItem chosen={chosen} index={i} key={id} price={price} name={name} onSelect={this.props.handleServiceItem} />
handleServiceItem
捕获从子进程传递的索引,并将其提供给其父进程[source]业主知道一切
该“所有权”的概念在React中是一个重要的概念 . 我建议阅读更多关于它here .
在我已经展示的示例中,我继续将事件的处理委托给组件树,直到我们到达拥有该状态的组件 .
当我们最终到达那里时,我们处理状态选择/取消选择,如此[source]:
结论
尽量保持最外层组件尽可能不透明 . 努力确保他们对父组件如何选择实现它们的偏好很少 .
了解谁拥有您正在操纵的数据 . 在大多数情况下,您需要将树的事件处理委托给拥有该状态的组件 .
旁白:Flux pattern是减少应用程序中此类必要连接的好方法 .
Edit :查看ES6更新示例的最终示例 .
这个答案只是处理直接父子关系的情况 . 如果父母和孩子可能有很多中间人,请查看answer .
其他解决方案都缺少这一点
虽然他们仍然工作正常,但其他答案缺少一些非常重要的答案 .
The parent already has that child prop! :如果孩子有道具,那是因为它的父母为孩子提供了道具!你为什么要让孩子把道具传回父母,而父母显然已经拥有那个道具?
更好的实施
Child :它确实不必比那更复杂 .
Parent with single child :使用传递给孩子的值
JsFiddle
Parent with list of children :您仍然拥有父母所需的一切,并且不需要让孩子更复杂 .
JsFiddle
也可以使用
this.handleChildClick.bind(null,childIndex)
然后使用this.state.childrenData[childIndex]
请注意,我们绑定了
null
上下文,否则React会发出与其autobinding系统相关的警告 . 使用null意味着您不想更改函数上下文 . See also .关于其他答案中的封装和耦合
在耦合和封装方面,这对我来说是一个很好的想法:
Using props :正如我上面所解释的那样,你已经拥有了父级中的道具,因此将整个子组件传递给访问道具是没用的 .
Using refs :您已经拥有事件中的点击目标,在大多数情况下这已经足够了 . 另外,您可以直接在孩子身上使用ref:
并访问父节点中的DOM节点
对于要在父级中访问子级的多个引用的更高级的情况,子级可以直接在回调中传递所有dom节点 .
该组件有一个接口(props),父节点不应该假设有关子内部工作的任何内容,包括它的内部DOM结构或它声明引用的DOM节点 . 使用儿童参考的父母意味着您紧密地耦合了2个组件 .
为了说明这个问题,我将引用关于Shadow DOM的引用,它在浏览器中用于渲染滑块,滚动条,视频播放器......:
问题是,如果您让子实现细节泄漏到父级,则很难在不影响父级的情况下重构子级 . 这意味着作为库作者(或作为带有Shadow DOM的浏览器编辑器),这非常危险,因为您让客户端访问太多,使得在不破坏反向兼容性的情况下升级代码非常困难 .
如果Chrome已实现其滚动条,让客户端访问该滚动条的内部dom节点,这意味着客户端可能会简单地破坏该滚动条,并且当Chrome在重构后执行其自动更新时,应用程序将更容易破解滚动条......相反,它们只能访问一些安全的东西,比如使用CSS自定义滚动条的某些部分 .
About using anything else
在回调中传递整个组件是危险的,并且可能导致新手开发人员做一些非常奇怪的事情,例如调用
childComponent.setState(...)
或childComponent.forceUpdate()
,或在父母内部分配新变量,使得整个应用程序更难以推理 .Edit: ES6 examples
现在许多人使用ES6,这里是ES6语法的相同示例
孩子可以很简单:
父可以是一个类(它最终可以管理状态本身,但我将它作为道具传递给它:
但如果它不需要管理状态,它也可以简化:
JsFiddle
PERF WARNING (适用于ES5 / ES6):如果您使用
PureComponent
或shouldComponentUpdate
,则上述实施将不会默认情况下优化,因为在渲染阶段使用onClick={e => doSomething()}
或直接绑定,因为每次父渲染时它都会创建一个新函数 . 如果这是您的应用程序中的性能瓶颈,您可以将数据传递给子项,并将其重新注入"stable"回调(在父类中设置,并绑定到类构造函数中的this
),以便PureComponent
优化可以启动,或者您可以实现自己的shouldComponentUpdate
并忽略props比较检查中的回调 .您还可以使用Recompose库,它提供更高阶的组件以实现微调优化:
在这种情况下,您可以使用以下方法优化Child组件: