具有深层分层数据的 ReactJS 数据流

Posted

技术标签:

【中文标题】具有深层分层数据的 ReactJS 数据流【英文标题】:ReactJS data flow with deep hierarchical data 【发布时间】:2015-09-04 16:19:46 【问题描述】:

我正在探索 ReactJS 并试图掌握核心概念。我开始拼凑我正在开发的应用程序的原型,该应用程序具有以下层次结构

客户 地点 地址 联系方式

我正在处理的页面将是客户及其所有相关子项的输入表单。这些部分中的每一个都有一些文本输入来存放数据,因此它们似乎是存放组件层次结构的自然场所。

从我所读到的关于 ReactJS 的所有内容中,如果你要管理状态,你应该在所有控件的共同祖先中这样做。这意味着孩子的任何变化都应该将事件冒泡到状态的保持者来处理变化。这应该会更新状态,并且任何更改都将重新呈现。这在简单的场景中是有道理的,但这使我进入了稍微复杂的层次结构。

如果在多个地址之一中发生更改,我是否应该将该事件冒泡到该位置,然后再发送给客户? 如果是这样,告诉 state 哪个特定地址已更改的最佳方法是什么? 如果您必须调用层次结构的每个级别,那会不会产生大量额外的样板来传播一个简单的更改? 我应该附加到每个文本框上的 onChange 事件,还是应该等到我提交表单来收集数据?

React 谈到 ReactLink (https://facebook.github.io/react/docs/two-way-binding-helpers.html) 是一种管理更复杂数据绑定的方法,但没有给出一个很好的例子来说明如何使用更大的层次结构来管理它。此外,它指出大多数应用程序不应该需要这个。嗯,这个应用程序真的不复杂,只是几个具有共享状态的嵌套控件。这就是 React 应该大放异彩的地方,所以我不会考虑立即跳到边缘案例解决方案。

【问题讨论】:

我认为您缺少的部分是如何操纵状态。在您的示例中,数据将在 Customer 中管理,然后通过 props 传递给您的其他组件。同样,您可以创建函数来处理更改 Customer 状态的事件,然后通过 props 将它们作为回调传递。然后子组件可以在事件发生时使用回调来改变状态。 @Mark 我也是这么理解的,但是一旦深入一层,就会通过多层组件发送回调。所以 Location 必须传递一个与其行为无关的回调。这就是 React 希望你处理的方式吗?如果是这样,那很好,只是感觉 React 的其他方面有多优雅有点笨拙。 是的,您必须通过多层组件传递回调。由于您使用的是 JSX,处理此问题的一种优雅方法是使用 JSX 传播属性 (facebook.github.io/react/docs/transferring-props.html),它允许您传递使用 ...this.props 接收的所有道具。这在通过多层组件传递许多道具时非常有用。 【参考方案1】:

我最近遇到了同样的难题 - React 文档在这方面不是很完整。这是我发现的一种工作方式:

var Parent = React.createClass(
    mixins: [React.addons.LinkedStateMixin],

    getInitialState: function() 
        return 
            p: 'Hello World',
            q: 'Click me if I\'m pink!',
            r: 'A'
        ;
    ,
    render: function() 
        return (
            <div className='parent'>
                <p>
                    <h3>Parent</h3>
                    <tt>
                        p: this.state.p<br />
                        q: this.state.q<br />
                        r: this.state.r
                    </tt>
                </p>

                <Child q = this.linkState('q')
                       p = this.linkState('p')
                       r = this.linkState('r') />
            </div>
        );
    
);
var Child = React.createClass(
    clicked: function() 
        this.props.q.requestChange("Thank you :)");
    ,
    render: function() 
        return (
            <div className='child'>
                <h3>Child</h3>

                <p>
                    <input valueLink=this.props.p />
                </p>

                <p>
                    <tt onClick=this.clicked>
                        this.props.q.value
                    </tt>
                </p>

                <select valueLink=this.props.r>
                    <option value='A'>A</option>
                    <option value='B'>B</option>
                </select>
            </div>
        );
    
);

React.render(<Parent />, document.body)

https://jsfiddle.net/cachvico/p81s75x5/

如果有人有任何改进,我会很高兴听到他们的消息!

【讨论】:

jsfiddle 给出了一些错误:Uncaught TypeError: undefined is not a function jsfiddle-integration.js:8 Uncaught TypeError: undefined is not a function 在常规 Chrome 43.0.2357.130 和 Firefox 38.0.5 中仍然为我工作【参考方案2】:

我经常遇到这样的副作用,即尽可能少地制作组件。

我不得不将 onChange 向下传递到层次结构的 4-5 级,因为实际状态处于最顶层(容器)。

这是一个例子:

<ProjectContainer>
  <ProjectComponent onProjectChange onProjectTaskChange onCommentChange>
    <ProjectTasksComponent onProjectTaskChange onCommentChange>
      <ProjectTaskComponent onProjectTaskChange onCommentChange>
        <ProjectTaskCommentsComponent onCommentChange>
          <ProjectTaskCommentComponent onCommentChange>

【讨论】:

据我所知,我已经习惯了 React 和 Angular 2 的组件结构,这是处理事情的默认方式。如果您想避免这种类型的模式,您可以查看 Flux 之类的模式,或者 Redux 之类的库来集中状态更改以完成单向数据流。

以上是关于具有深层分层数据的 ReactJS 数据流的主要内容,如果未能解决你的问题,请参考以下文章

为具有关系的分层内容选择啥数据库?

从具有复合(分层)索引的 Pandas 数据框中选择行

在具有分层数据模板的树视图中绑定上下文菜单命令

如何使用具有多对多连接到同一个表的 JPA 分层检索数据

以高写入负载在 MySQL 中存储分层数据

具有分层 Web 应用程序的实体框架