将道具传递给React.js中的父组件 [英] Pass props to parent component in React.js

查看:119
本文介绍了将道具传递给React.js中的父组件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有一种简单的方法可以使用React.js中的事件将子项的 props 传递给其父项?

Is there not a simple way to pass a child's props to its parent using events, in React.js?

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。有时,子组件包含一组您不必查找的信息。

I know you can use controlled components to pass an input's value but it'd be nice to pass the whole kit n' kaboodle. Sometimes the child component contains a set of information you'd rather not have to look up.

也许有一种方法可以将组件绑定到事件中?

Perhaps there's a way to bind the component to the event?

使用React超过一年后,在Sebastien Lorber的回答刺激下,我已经总结传递子组件作为父母函数的参数实际上是React方式,也不是一个好主意。我已经改变了答案。

After using React for over a year, and spurred on by Sebastien Lorber's answer, I've concluded passing child components as arguments to functions in parents is not in fact the React way, nor was it ever a good idea. I've switched the answer.

推荐答案

编辑:请参阅ES6更新示例的最终示例。

Edit: see the end examples for ES6 updated examples.

这个答案只是处理直接父子关系的情况。如果父母和孩子可能有很多中间人,请查看答案

This answer simply handle the case of direct parent-child relationship. When parent and child have potentially a lot of intermediaries, check this answer.

虽然它们仍能正常工作,但其他答案缺少一些非常重要的答案。

While they still work fine, other answers are missing something very important.


在React.js中,是否有一种简单的方法可以使用事件将子项的道具传递给它的父项?

Is there not a simple way to pass a child's props to its parent using events, in React.js?

父母已经有了这个孩子道具!:如果孩子有道具,那是因为它的父母为孩子提供了道具!为什么你希望孩子将道具传回父母,而父母显然已经拥有该道具?

The parent already has that child prop!: if the child has a prop, then it is because its parent provided that prop to the child! Why do you want the child to pass back the prop to the parent, while the parent obviously already has that prop?

孩子:它确实不必比那更复杂。

Child: it really does not have to be more complicated than that.

var Child = React.createClass({
  render: function () {
    return <button onClick={this.props.onClick}>{this.props.text}</button>;
  },
});

有单个孩子的父母:使用传递给孩子的值

Parent with single child: using the value it passes to the child

var Parent = React.createClass({
  getInitialState: function() {
     return {childText: "Click me! (parent prop)"};
  },
  render: function () {
    return (
      <Child onClick={this.handleChildClick} text={this.state.childText}/>
    );
  },
  handleChildClick: function(event) {
     // You can access the prop you pass to the children 
     // because you already have it! 
     // Here you have it in state but it could also be
     //  in props, coming from another parent.
     alert("The Child button text is: " + this.state.childText);
     // You can also access the target of the click here 
     // if you want to do some magic stuff
     alert("The Child HTML is: " + event.target.outerHTML);
  }
});

JsFiddle

包含孩子列表的父母:您仍然拥有父母所需的一切,而不需要制作孩子更复杂。

Parent with list of children: you still have everything you need on the parent and don't need to make the child more complicated.

var Parent = React.createClass({
  getInitialState: function() {
     return {childrenData: [
         {childText: "Click me 1!", childNumber: 1},
         {childText: "Click me 2!", childNumber: 2}
     ]};
  },
  render: function () {
    var children = this.state.childrenData.map(function(childData,childIndex) {
        return <Child onClick={this.handleChildClick.bind(null,childData)} text={childData.childText}/>;
    }.bind(this));
    return <div>{children}</div>;
  },

  handleChildClick: function(childData,event) {
     alert("The Child button data is: " + childData.childText + " - " + childData.childNumber);
     alert("The Child HTML is: " + event.target.outerHTML);
  }
});

JsFiddle

也可以使用 this.handleChildClick.bind(null,childIndex)然后使用 this.state.childrenData [childIndex]

注意我们绑定 null context,因为否则React会发出与其相关的警告 autobinding 系统。使用null意味着您不想更改函数上下文。 另见

Note we are binding with a null context because otherwise React issues a warning related to its autobinding system. Using null means you don't want to change the function context. See also.

这对我来说是一个错误的想法,在耦合和封装方面:

This is for me a bad idea in term of coupling and encapsulation:

var Parent = React.createClass({
  handleClick: function(childComponent) {
     // using childComponent.props
     // using childComponent.refs.button
     // or anything else using childComponent
  },
  render: function() {
    <Child onClick={this.handleClick} />
  }
});

使用道具
如上所述,你已经在父级中拥有道具,因此将整个子组件传递给访问道具是没用的。

Using props: As I explained above, you already have the props in the parent so it's useless to pass the whole child component to access props.

使用refs
你已经在事件中有点击目标,在大多数情况下这就足够了。
另外,您可以直接在孩子身上使用参考:

Using refs: You already have the click target in the event, and in most case this is enough. Additionnally, you could have used a ref directly on the child:

<Child ref="theChild" .../>

并使用

React.findDOMNode(this.refs.theChild)

对于要在父级中访问子级的多个引用的更高级的情况,子级可以直接在回调中传递所有dom节点。

For more advanced cases where you want to access multiple refs of the child in the parent, the child could pass all the dom nodes directly in the callback.

组件具有一个接口(props)和父进程不应该假设有关子进程的内部工作,包括它的内部DOM结构或它声明引用的DOM节点。使用孩子参考的父母意味着你紧密地耦合了2个组件。

The component has an interface (props) and the parent should not assume anything about the inner working of the child, including its inner DOM structure or which DOM nodes it declares refs for. A parent using a ref of a child means that you tightly couple the 2 components.

为了说明这个问题,我将引用关于 Shadow DOM ,用于在浏览器内部渲染滑块等内容,滚动条,视频播放器...:

To illustrate the issue, I'll take this quote about the Shadow DOM, that is used inside browsers to render things like sliders, scrollbars, video players...:


他们在你,网络开发者可以达到
和什么是考虑了实施细节,因此你无法获得
。然而,浏览器可以随意跨越这个边界。
有了这个边界,他们能够使用相同的古老的Web技术构建所有HTML元素
,在div和跨越
就像你一样。

They created a boundary between what you, the Web developer can reach and what’s considered implementation details, thus inaccessible to you. The browser however, can traipse across this boundary at will. With this boundary in place, they were able to build all HTML elements using the same good-old Web technologies, out of the divs and spans just like you would.

问题在于,如果让子实现细节泄漏到父级中,则很难在不影响父级的情况下重构子级。这意味着作为库作者(或作为带有Shadow DOM的浏览器编辑器),这非常危险,因为您让客户端访问太多,使得在不破坏后向兼容性的情况下升级代码非常困难。

The problem is that if you let the child implementation details leak into the parent, you make it very hard to refactor the child without affecting the parent. This means as a library author (or as a browser editor with Shadow DOM) this is very dangerous because you let the client access too much, making it very hard to upgrade code without breaking retrocompatibility.

如果Chrome已实现其滚动条,让客户端访问该滚动条的内部dom节点,这意味着客户端可能会简单地破坏该滚动条,并且当​​Chrome执行其自动操作时应用程序将更容易破解重构滚动条后更新...相反,它们只能访问一些安全的东西,比如用CSS自定义滚动条的某些部分。

If Chrome had implemented its scrollbar letting the client access the inner dom nodes of that scrollbar, this means that the client may have the possibility to simply break that scrollbar, and that apps would break more easily when Chrome perform its auto-update after refactoring the scrollbar... Instead, they only give access to some safe things like customizing some parts of the scrollbar with CSS.

关于使用任何东西否则

在回调中传递整个组件是危险的,可能会导致新手开发人员做一些非常奇怪的事情,如调用 childComponent.setState (...) childComponent.forceUpdate(),或在父级内部分配新变量,使整个应用程序muc更难以推理。

Passing the whole component in the callback is dangerous and may lead novice developers to do very weird things like calling childComponent.setState(...) or childComponent.forceUpdate(), or assigning it new variables, inside the parent, making the whole app much harder to reason about.

编辑:ES6示例

现在很多人都使用ES6,这里是ES6语法的相同例子

As many people now use ES6, here are the same examples for ES6 syntax

孩子可以非常简单:

const Child = ({
  onClick, 
  text
}) => (
  <button onClick={onClick}>
    {text}
  </button>
)

父级可以是一个类(它最终可以管理状态本身,但我在这里将它作为道具传递:

The parent can be either a class (and it can eventually manage the state itself, but I'm passing it as props here:

class Parent1 extends React.Component {
  handleChildClick(childData,event) {
     alert("The Child button data is: " + childData.childText + " - " + childData.childNumber);
     alert("The Child HTML is: " + event.target.outerHTML);
  }
  render() {
    return (
      <div>
        {this.props.childrenData.map(child => (
          <Child
            key={child.childNumber}
            text={child.childText} 
            onClick={e => this.handleChildClick(child,e)}
          />
        ))}
      </div>
    );
  }
}

但它也可以是如果不需要管理stat,则简化e:

But it can also be simplified if it does not need to manage state:

const Parent2 = ({childrenData}) => (
  <div>
     {childrenData.map(child => (
       <Child
         key={child.childNumber}
         text={child.childText} 
         onClick={e => {
            alert("The Child button data is: " + child.childText + " - " + child.childNumber);
                    alert("The Child HTML is: " + e.target.outerHTML);
         }}
       />
     ))}
  </div>
)

JsFiddle

PERF WARNING (适用于ES5 / ES6):如果你正在使用 PureComponent shouldComponentUpdate ,默认情况下不会优化上述实现,因为使用 onClick = {e => doSomething()} ,或者在渲染阶段直接绑定,因为每次父渲染时它都会创建一个新函数。如果这是您的应用程序中的性能瓶颈,您可以将数据传递给子项,并将其重新注入稳定回调(在父类上设置,并绑定到在类构造函数中)以便 PureComponent 优化可以启动,或者您可以实现自己的 shouldComponentUpdate 并忽略回调在道具比较检查中。

PERF WARNING (apply to ES5/ES6): if you are using PureComponent or shouldComponentUpdate, the above implementations will not be optimized by default because using onClick={e => doSomething()}, or binding directly during the render phase, because it will create a new function everytime the parent renders. If this is a perf bottleneck in your app, you can pass the data to the children, and reinject it inside "stable" callback (set on the parent class, and binded to this in class constructor) so that PureComponent optimization can kick in, or you can implement your own shouldComponentUpdate and ignore the callback in the props comparison check.

您还可以使用重新组合库,提供更高阶的组件以实现微调优化:

You can also use Recompose library, which provide higher order components to achieve fine-tuned optimisations:

// A component that is expensive to render
const ExpensiveComponent = ({ propA, propB }) => {...}

// Optimized version of same component, using shallow comparison of props
// Same effect as React's PureRenderMixin
const OptimizedComponent = pure(ExpensiveComponent)

// Even more optimized: only updates if specific prop keys have changed
const HyperOptimizedComponent = onlyUpdateForKeys(['propA', 'propB'])(ExpensiveComponent)

在这种情况下,您可以使用以下方法优化子组件:

In this case you could optimize the Child component by using:

const OptimizedChild = onlyUpdateForKeys(['text'])(Child)

这篇关于将道具传递给React.js中的父组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆