【问题标题】:Where do sockets fit into the Flux unidirectional data flow?套接字在哪里适合 Flux 单向数据流?
【发布时间】:2015-08-09 01:03:51
【问题描述】:

套接字在 Flux 单向数据流中的位置是什么?我已经阅读了 2 个关于远程数据应该在哪里进入 Flux 单向数据流的观点。我看到获取 Flux 应用程序的远程数据的方式是在进行服务器端调用时,例如,在随后被解决或拒绝的承诺中。在此过程中可能会触发三种可能的操作:

  1. 乐观地更新视图的初始操作(FooActions.BAR)
  2. 异步承诺解决时的成功操作(FooActions.BAR_SUCCESS)
  3. 异步承诺被拒绝时的错误操作(FooActions.BAR_ERROR)

商店将监听操作并更新必要的数据。我已经看到了来自动作创建者和商店本身的服务器端调用。我在上述过程中使用动作创建器,但我不确定是否应该对通过 Web 套接字获取的数据进行类似处理。我想知道插座适合下图中的哪个位置。

【问题讨论】:

  • 您所拥有的图表代表了客户端自身包含的东西(没有服务器)。如果您正在寻找与服务器通信的东西,请查看此处的图表github.com/facebook/flux
  • 如果您以类似 HTTP 的方式(请求/响应)使用 websocket,我会将其视为几乎完全一样的 HTTP 请求。如果数据不断流入 websocket,我会在 websocket 上设置监听器,在接收到数据时将操作推送到调度程序。

标签: javascript websocket socket.io reactjs flux


【解决方案1】:

你如何使用 Flux 和 WebSockets 或普通的旧 HTTP 请求/轮询并没有什么不同。您的商店负责在应用程序状态更改时发出更改事件,如果该更改来自 UI 交互、WebSocket 或发出 HTTP 请求,则不应从商店外部可见。这确实是 Flux 的主要优点之一,因为无论应用程序状态在哪里更改,它都会通过相同的代码路径。

一些 Flux 实现倾向于使用动作/动作创建者来获取数据,但我不太同意。

动作是发生改变您的应用程序状态的事情。例如“用户更改了一些文本并点击保存”或“用户删除了一个项目”。想想像数据库的事务日志这样的操作。如果您丢失了数据库,但您保存并序列化了曾经发生的所有操作,您可以重放所有这些操作并最终得到您丢失的相同状态/数据库。

所以像“给我带有 id X 的物品”和“给我所有的物品”之类的东西不是动作,它们是问题,关于那个应用程序状态的问题。在我看来,应该由商店通过您在这些商店中公开的方法来回答这些问题。

使用动作/动作创建者来获取是很有诱惑力的,因为获取需要是异步的。通过将异步内容包装在操作中,您的组件和存储可以完全同步。但是如果你这样做,你会模糊一个动作的定义,它也会迫使你假设你可以在内存中适应你的整个应用程序状态(因为如果你在内存中有答案,你只能同步响应)。

以下是我对 Flux 和不同概念的看法。

商店

这显然是您的应用程序状态所在的位置。 store 封装和管理状态,并且是该状态实际发生突变的唯一地方。它也是当状态改变时发出事件的地方。

商店还负责与后端进行通信。当状态发生变化并且需要与服务器同步时,存储与后端通信,当它需要内存中没有的数据时,它也会与服务器通信。它有get(id)、search(parameters) 等方法。这些方法是针对你的问题的,它们都返回承诺,即使状态可以放入内存。这很重要,因为您最终可能会遇到状态不再适合内存的用例,或者无法在内存中过滤或进行高级搜索的用例。通过从您的问题方法返回承诺,您可以在从内存返回或询问后端之间切换,而无需更改存储之外的任何内容。

操作

我的操作非常轻量级,他们对持久化封装的突变一无所知。他们只是带着从组件到商店变异的意图。对于较大的应用程序,它们可以包含一些逻辑,但不能包含服务器通信之类的东西。

组件

这些是你的 React 组件。他们通过调用商店上的问题方法并呈现这些方法的返回值来与商店交互。他们还订阅了商店公开的change 事件。我喜欢使用高阶组件,这些组件只是包装另一个组件并将道具传递给它。一个例子是:

var TodoItemsComponent = React.createClass({
  getInitialState: function () {
    return {
      todoItems: null
    }
  },
  componentDidMount: function () {
    var self = this;
    TodoStore.getAll().then(function (todoItems) {
      self.setState({todoItems: todoItems});
    });

    TodoStore.onChange(function (todoItems) {
      self.setState({todoItems: todoItems});
    });
  },
  render: function () {
    if (this.state.todoItems) {
      return <TodoListComponent todoItems={this.state.todoItems} />;
    } else {
      return <Spinner />;
    }
  }
});

var TodoListComponent = React.createClass({
  createNewTodo: function () {
    TodoActions.createNew({
      text: 'A new todo!'
    });
  },
  render: function () {
    return (
      <ul>
        {this.props.todoItems.map(function (todo) {
          return <li>{todo.text}</li>;
        })}
      </ul>
      <button onClick={this.createNewTodo}>Create new todo</button>
    );
  }
});

在这个例子中,TodoItemsComponent 是高阶组件,它包含了与商店通信的细节。它在获取待办事项后渲染TodoListComponent,并在此之前渲染一个微调器。由于它将待办事项作为道具传递给TodoListComponent,因此该组件只需专注于渲染,并且一旦商店中发生任何变化,它就会重新渲染。并且渲染组件保持完全同步。另一个好处是TodoItemsComponent 只专注于获取数据并将其传递,这使得它对于任何需要 todos 的渲染组件都非常可重用。

高阶组件

术语高阶组件来自术语高阶函数。高阶函数是返回其他函数的函数。所以高阶组件是一个组件,它只是包装了另一个组件并返回它的输出。

【讨论】:

  • 并非所有人都同意商店应该与 Web 服务器进行通信。事实上,很多人都没有。 stackoverflow.com/q/25630611/95190
  • 这是真的,我希望我没有像我的观点那样说实话。这就是我如何解释 Flux 和它的力量。我很可能会改变我对在行动中进行服务器通信的想法。 Flux 与 MVC 一样模棱两可,因为它“只是”一个想法,并且可以对它有不同的解释,而没有任何一个是错误的。
  • 您的回答听起来确实是事实。例如,“商店也负责与后端通信。”
  • 我认为答案是好的,尤其是考虑到“这就是我如何看待 Flux 和不同的概念”
  • 虽然商店进行沟通是值得商榷的,但就是这样:值得商榷。很多人都在使用商店进行交流,如果它更适合您的应用程序,那么有很多充分的理由这样做。商店不应该交流绝不是必然的。
猜你喜欢
  • 1970-01-01
  • 2017-01-17
  • 1970-01-01
  • 1970-01-01
  • 2017-11-09
  • 2016-03-03
  • 2011-11-30
  • 1970-01-01
  • 2016-04-02
相关资源
最近更新 更多