套接字在哪里适合Flux单向数据流?

时间:2015-05-27 05:44:37

标签: javascript websocket socket.io reactjs flux

套接字在哪里适合Flux单向数据流?我已经阅读了两种思路,即远程数据应该进入Flux单向数据流。我看到获取Flux应用程序的远程数据的方式是在进行服务器端调用时,例如,在承诺中解析或拒绝。在此过程中可能会触发三种可能的行动:

  1. 乐观更新视图(FooActions.BAR)
  2. 的初始操作
  3. 解决异步承诺的成功操作(FooActions.BAR_SUCCESS)
  4. 异步承诺被拒绝时的错误操作(FooActions.BAR_ERROR)
  5. 商店将监听操作并更新必要的数据。我已经看到了来自动作创建者和商店内部的服务器端调用。我使用动作创建器进行上述过程,但我不确定是否应该类似地处理通过Web套接字获取的数据。我想知道插座适合下图。

    enter image description here

1 个答案:

答案 0 :(得分:10)

使用Flux与WebSockets或普通的旧HTTP请求/轮询的方式确实没有区别。当应用程序状态发生变化时,您的商店负责发出更改事件,如果该更改来自UI交互,WebSocket或发出HTTP请求,则不应从商店外部看到它。这确实是Flux的主要优点之一,无论应用程序状态在哪里发生变化,它都会经历相同的代码路径。

一些Flux实施倾向于使用动作/动作创建者来获取数据,但我并不十分赞同。

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

所以"给我一个id为X"并且"给我所有的项目"不是行动,他们是关于该申请状态的问题和问题。在我看来,应该通过您在这些商店中公开的方法回应这些问题的商店。

使用动作/动作创建器进行抓取很诱人,因为抓取需要异步。通过将异步内容包装在操作中,您的组件和存储可以完全同步。但是,如果你这样做,你会模糊一个动作的定义,它也会迫使你假设你可以将你的整个应用程序状态放在内存中(因为你只能在内存中得到答案时才能同步响应)。 / p>

所以这里是我如何看待Flux和不同的概念。

<强>店铺

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

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

操作

我的行为非常轻量级,而且他们对于持久化它们所包含的突变一无所知。他们只是意图从组件变异到商店。对于较大的应用程序,它们可以包含一些逻辑,但绝不会包含服务器通信。

<强>零件

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

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,并在此之前呈现一个微调器。因为它将todo项目作为道具传递给TodoListComponent,组件只需要专注于渲染,并且只要商店中的任何内容发生变化,它就会被重新渲染。并且渲染组件保持完全同步。另一个好处是TodoItemsComponent仅专注于获取数据并将其传递,使其对于需要todos的任何渲染组件都非常可重用。

更高阶的组件

术语高阶组件来自术语高阶函数。高阶函数是返回其他函数的函数。因此,更高阶的组件是一个只包装另一个组件并返回其输出的组件。