React:将子状态传递给父状态

Posted

技术标签:

【中文标题】React:将子状态传递给父状态【英文标题】:React: Passing child state to parent state 【发布时间】:2019-03-08 19:44:36 【问题描述】:

我已经在 React 工作了一年多,我读过 Thinking in react、Lifting state up 和 State and lifecycle。

我了解到React的数据流概​​念是单向数据流

来自这些页面的引用:

React 的单向数据流(也称为单向绑定)使一切都模块化且快速。

记住:React 是关于单向数据沿着组件层次结构向下流动的。可能无法立即清楚哪个组件应该拥有什么状态。这通常是新手最难理解的部分,所以请按照以下步骤来弄清楚:...

如果您将组件树想象为道具的瀑布,则每个组件的状态就像一个额外的水源,在任意点加入它,但也会向下流动。

据我了解,以下示例是不允许的,因为我将子 state 数据传递给父级。但我看到一些开发人员是这样工作的:

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>;
    

我现在的问题是:

真的不允许吗? 为什么不应该是模块化和快速的? 这真的会阻止单向数据流,变成双向数据流吗? 这种方式还会出现什么其他问题? 当我将状态提升时,您将如何解决以下情况; 50 个使用该子组件的具体父级,每个父级是否应该为他们正在使用的同一个子级具有相同的初始化子状态?

【问题讨论】:

这对我来说看起来不错 - 单向数据流并不意味着没有孩子到父母的通信,它只是意味着你不应该有相同的状态被存储/修改多个地方。在您的示例中,存储在父状态和子状态中的数据并不完全相同 - 您的子组件存储表单的 current 状态(无论用户是否已提交),而父组件存储用户提交的具体数据。 在您有 50 位父母的情况下,我想说这取决于这 50 位父母是否需要了解彼此 - 如果不需要,您可能会摆脱存储直接在父母中的数据,但如果他们都需要知道提交的数据的所有,你最好将它传递到另一层(再次通过回调道具)到公共父母。 【参考方案1】:

这真的不允许吗? 为什么这不应该是模块化和快速的?

很好的问题。这是允许的。让它正常工作有点棘手,因为你在这里有状态同步。在现代前端世界中,状态同步被认为是一项非常具有挑战性的任务。

当您需要在两个方向上同步状态时,就会出现问题。例如,如果此子表单用于编辑列表的某个元素,而您正在更改列表的当前元素。在特定的 UI 更新期间,您将需要子组件来检测这种情况并将其本地状态与来自 props 的新元素同步。只要你没有那个,你就没事。

这真的会阻止单向数据流,变成双向数据流吗?

不,不是。它仍然是单向数据流,因为 React 在设计上不能以任何其他方式工作; UI 更新总是从上到下。在您的示例中,您的孩子触发了一个事件,该事件导致父母更新其状态(完全没问题),这将导致父母 孩子的 UI 更新。如果你真的违反了“单向数据流”,你会感觉到的。你会得到一个无限循环或类似的东西。

当我将状态提升时,您将如何解决以下情况; 50 个使用该子组件的具体父组件,每个父组件是否应该为他们正在使用的同一个子组件具有相同的初始化子状态?

是的,这就是他们所说的“提升国家”的意思。您将根状态组织为反映子节点状态的树,然后将状态元素连同回调一起传递给子节点以修改根状态。

【讨论】:

好的,所以我的例子似乎是从孩子到父母的单向状态值同步,应该允许。但是,当我将父 state value 作为道具传递给孩子时,将该道具设置为孩子的状态,然后通过回调将此孩子的状态值传递回其父母,将其设置为父母的状态,这将是一个问题,因为这将是两个方向的状态同步。对吗? 我认为这不是问题,因为要将值从子节点传播到父节点,您总是必须触发一个事件,并且反应的设计会自动从父节点传播到子节点。所以你不能以无限循环结束【参考方案2】:

这是允许的,您的代码没有任何问题,但我不会称其为将状态从子级传递给父级。您所做的只是调用在 props 中传递的方法,并由带有一些参数的事件触发,在您的示例中是孩子的状态值,但它可以是任何其他变量。父组件对此参数的性质一无所知,它只是接收该值并能够对它做任何事情,例如将它自己的状态更改为另一个。如果 Child 的状态将更改,则 Parent 不会在没有再次触发 onSubmit 事件的情况下接收此更新。但是孩子总是从父母那里收到更新,并在道具发生变化时自动重新渲染。当然,有些道具可能是一些父母的状态。这是行为上的主要区别。

有一篇很好的文章详细解释了这一点:Props down, Events Up

【讨论】:

非常感谢,但是对于文章 Props down, Events Up,这是许多展示如何将 事件 数据传递给父级而不是 的示例状态 数据给父母。对我来说,正如我最初理解的文档一样,从子级到父级的 state 数据不应像 event 数据那样传递。所以我不确定我们是否遗漏了什么,尽管你自己的状态论证听起来是有效的。【参考方案3】:

您的问题是绝对正确的,很多时候开发人员(包括我自己)都在为将子组件状态或道具传递给父组件而苦苦挣扎。

我总是在子组件中获取下一个状态或下一个道具的逻辑,并通过使用父组件的处理函数将下一个状态或下一个道具传递给父组件。

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"));

【讨论】:

您的意见/经验是什么,为什么要使用 nextStete/nextProps 以及为什么这比问题中的示例更好?您仍在将子状态数据传递给父级。 最佳实践是始终对数据使用单一事实来源,这意味着在 UI 中更改数据的唯一方法。我有超过 2 年的 React 经验。这就是我向您展示我处理状态的方法的原因。

以上是关于React:将子状态传递给父状态的主要内容,如果未能解决你的问题,请参考以下文章

将子组件的状态传递给父组件?

我如何在 reactjs + typescript (钩子)中使用 useRef 将子状态值传递给父级

React - 在下拉选择中将状态从子级传递给父级

如何在反应中将最新状态从子组件传递给父组件

在选择选项更改时将子组件中的道具传递给父组件

【Flutter】多组件共用状态,父组件状态传递给子组件