你如何使用 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 的渲染组件都非常可重用。
高阶组件
术语高阶组件来自术语高阶函数。高阶函数是返回其他函数的函数。所以高阶组件是一个组件,它只是包装了另一个组件并返回它的输出。