简体   繁体   English

反应:将子状态传递给父状态

[英]React: Passing child state to parent state

I am working since more than a year with React and i have read Thinking in react , Lifting state up , and State and lifecycle . 我在React从事工作已经有一年多了,并且阅读了React中的思考提升状态以及State和生命周期

I have learned that React's concept with data flow is is One-way data flow . 我了解到,React的数据流概​​念是单向数据流

Citates from these pages: 从这些页面引用:

React's one-way data flow (also called one-way binding) keeps everything modular and fast. React的单向数据流(也称为单向绑定)使一切保持模块化和快速。

Remember: React is all about one-way data flow down the component hierarchy. 记住:React是关于组件层次结构中的单向数据流。 It may not be immediately clear which component should own what state. 可能尚不清楚哪个组件应拥有什么状态。 This is often the most challenging part for newcomers to understand, so follow these steps to figure it out:... 对于新手来说,这通常是最具挑战性的部分,因此请按照以下步骤进行操作:...

If you imagine a component tree as a waterfall of props, each component's state is like an additional water source that joins it at an arbitrary point but also flows down. 如果您将一棵组件树想象成道具的瀑布,那么每个组件的状态就像是一个附加的水源,该水源在任意点处将其加入,但还会向下流动。

As i understand this, following example is not allowed because i am passing child state data to the parent. 据我了解,以下示例是不允许的,因为我正在将子状态数据传递给父级。 But i see some developers working like that: 但是我看到一些开发人员像这样工作:

class Parent extends React.Component {
    constructor(props) {
        super(props);
        this.state = { fromParent: null };
    }

    addSomething(stateValueFromChild) {
        this.setState({fromParent: stateValueFromChild});
    }

    render() {
        return <Child
                addSomething={(stateValueFromChild) => this.addSomething(stateValueFromChild)}>
                 // ...
        </Child>;
    }
}

class Child extends React.Component {
    constructor(props) {
        super(props);
        this.state = { fromChild: 'foo' };
    }

    render() {
        return <Form onSubmit={() => this.props.addSomething(this.state.fromChild)}>
                 // ...
        </Form>;
    }
}

My questions now are: 我的问题是:

  • Is this really not allowed? 真的不允许这样做吗?
  • Why should this not be modular and fast? 为什么这不应该模块化且快速?
  • Is this really braking the one-way-dataflow, becoming a two way dataflow? 这真的是在阻止单向数据流,变成了双向数据流吗?
  • What other problems could happen with this way? 这种方式还会发生什么其他问题?
  • When i would lift the state up, how would you solve following case; 当我提起状态时,您将如何解决以下情况; 50 concrete parents that uses that child component, should every parent have a same initialized sub-state for the same child that they are using? 50个使用该子组件的具体父母,是否每个父母都对他们正在使用的同一个孩子具有相同的初始化子状态?

It's allowed and there is nothing wrong with your code, but I would not call it passing state from child to parent. 这是允许的,您的代码没有任何问题,但是我不会将其从子级传递到父级。 All you do is invoking method passed in props and triggered by event with some argument, which in your example is child's state value, but it could be any other variable. 您要做的只是调用在props中传递并由事件触发的带有一些参数的方法,在您的示例中,该方法是child的state值,但是它可以是任何其他变量。 Parent component knows nothing about nature of this argument, it just receives the value and able to do anything with it, for example change it's own state to another. 父组件对此参数的性质一无所知,它仅接收该值并能够执行任何操作,例如将其自身的状态更改为另一个状态。 If Child's state will change, Parent is not going to receive this update without onSubmit event fired again. 如果孩子的状态将改变, 则在再次触发onSubmit事件之前,父对象将不会收到此更新。 But children always receive updates from the parent and automatically get rerendered, when props get changed. 但是,孩子总是会收到父母的更新,并在更改道具时自动将其重新呈现。 And of course some of the props could be states of some parents. 当然,某些道具可能是某些父母的状态。 Here is the major difference in behavior. 这是行为上的主要区别。

There is a good article explaining this in details: Props down, Events Up 有一篇很好的文章详细解释了这一点: 道具减少,事件增加

Is this really not allowed? 真的不允许这样做吗? Why should this not be modular and fast? 为什么这不应该模块化且快速?

Excellent questions. 很好的问题。 This is allowed. 这是允许的。 It's just a bit tricky to make it work right because you've got state synchronization here. 使它正常工作有点棘手,因为这里有状态同步 In the modern frontend world, the state synchronization is believed to be a very challenging task. 在现代的前端世界中,状态同步被认为是一项非常具有挑战性的任务。

The problem will appear when you'll need to sync the state in two directions. 当您需要在两个方向上同步状态时,将出现问题。 For instance, if this child form is used to edit some element of the list, and you're changing the current element of the list. 例如,如果此子窗体用于编辑列表的某些元素,而您正在更改列表的当前元素。 You'll need the child component to detect that situation and sync its local state with the new element from props during the particular UI update. 您将需要子组件来检测这种情况,并在特定的UI更新期间将其本地状态与props中的新元素同步。 As long as you don't have that, you're fine. 只要您没有,就可以了。

Is this really braking the one-way-dataflow, becoming a two way dataflow? 这真的是在阻止单向数据流,变成了双向数据流吗?

Nah, it's not. 不,不是。 It's still unidirectional data flow because React can't work in any other way by design; 它仍然是单向数据流,因为React在设计上无法以任何其他方式工作; UI updates always coming from top to bottom. UI更新始终从上到下进行。 In your example, your child triggers an event which causes the parent to update its state (it's totally fine), which will cause the UI update of the parent and the child. 在您的示例中,您的孩子触发了一个事件,该事件导致父级更新其状态(完全正常),这将导致父级子级的UI更新。 If you really violate "unidirectional data flow", you'll feel it. 如果您确实违反了“单向数据流”,您会感到无所适从。 You will get an infinite loop or something similar. 您将获得无限循环或类似的结果。

When i would lift the state up, how would you solve following case; 当我提起状态时,您将如何解决以下情况; 50 concrete parents that uses that child component, should every parent have a same initialized sub-state for the same child that they are using? 50个使用该子组件的具体父母,是否每个父母都对他们正在使用的同一个孩子具有相同的初始化子状态?

Yep, that's what they mean by "lifting the state". 是的,这就是“解除国家”的含义。 You organize your root state as a tree reflecting the state of the children, then pass down elements of the state to children along with callbacks to modify the root state. 您将根状态组织为一棵反映子状态的树,然后将状态元素与回调一起传递给子状态以修改根状态。

Your question is absolutely correct, many times developer (including myself) struggled for passing child's components state or props to parent component. 您的问题是绝对正确的,很多时候开发人员(包括我自己)都在努力将子组件的状态或道具传递给父组件。

I always do logic for getting next state or next props in child component and pass next state or next props to parent component by using handler functions of parent component. 我总是做逻辑来获取子组件中的下一个状态或下一个道具,并通过使用父组件的处理函数将下一个状态或下一个道具传递给父组件。

import React, { Component } from "react";
import { render } from "react-dom";

class Parent extends Component {
  constructor(props) {
    super(props);
    this.handleSomething = this.handleSomething.bind(this); // binding method
    this.state = {
      fromParent: "foo"
    };
  }

  handleSomething(value) {
    this.setState(prevState => {
      return {
        fromParent: value
      };
    });
  }

  render() {
    return (
      <div>
        <h1>State: {this.state.fromParent}</h1>
        <Child handleSomething={this.handleSomething} />
      </div>
    );
  }
}

class Child extends Component {
  constructor(props) {
    super(props);
    this.state = {
      fromChild: "bar"
    };
  }

  render() {
    return (
      <div>
        <button
          onClick={e => {
            const { fromChild } = this.state;
            // do whatever as per your logic for get value from child pass to handleSomething function
            // you can also do same for handling forms
            this.props.handleSomething(fromChild);
          }}
        >
          Click Me
        </button>
      </div>
    );
  }
}

render(<Parent />, document.getElementById("app"));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM