九、致谢

最后更新于:2022-04-01 22:36:26

## 九、致谢 本文受到了Andrew Ray 的文章[《Flux For Stupid People》](http://blog.andrewray.me/flux-for-stupid-people/)的启发。 (完)
';

八、View (第二部分)

最后更新于:2022-04-01 22:36:24

## 八、View (第二部分) 现在,我们再回过头来修改 [View](https://github.com/ruanyf/extremely-simple-flux-demo/blob/master/components/MyButtonController.jsx) ,让它监听 Store 的 `change` 事件。 > ~~~ > // components/MyButtonController.jsx > var React = require('react'); > var ListStore = require('../stores/ListStore'); > var ButtonActions = require('../actions/ButtonActions'); > var MyButton = require('./MyButton'); > > var MyButtonController = React.createClass({ > getInitialState: function () { > return { > items: ListStore.getAll() > }; > }, > > componentDidMount: function() { > ListStore.addChangeListener(this._onChange); > }, > > componentWillUnmount: function() { > ListStore.removeChangeListener(this._onChange); > }, > > _onChange: function () { > this.setState({ > items: ListStore.getAll() > }); > }, > > createNewItem: function (event) { > ButtonActions.addNewItem('new item'); > }, > > render: function() { > return items={this.state.items} > onClick={this.createNewItem} > />; > } > }); > ~~~ 上面代码中,你可以看到当`MyButtonController` 发现 Store 发出 `change` 事件,就会调用 `this._onChange` 更新组件状态,从而触发重新渲染。 > ~~~ > // components/MyButton.jsx > var React = require('react'); > > var MyButton = function(props) { > var items = props.items; > var itemHtml = items.map(function (listItem, i) { > return
  • {listItem}
  • ; > }); > > return
    >
      {itemHtml}
    > >
    ; > }; > > module.exports = MyButton; > ~~~
    ';

    七、Store

    最后更新于:2022-04-01 22:36:22

    ## 七、Store Store 保存整个应用的状态。它的角色有点像 MVC 架构之中的Model 。 在我们的 Demo 中,有一个[`ListStore`](https://github.com/ruanyf/extremely-simple-flux-demo/blob/master/stores/ListStore.js),所有数据都存放在那里。 > ~~~ > // stores/ListStore.js > var ListStore = { > items: [], > > getAll: function() { > return this.items; > }, > > addNewItemHandler: function (text) { > this.items.push(text); > }, > > emitChange: function () { > this.emit('change'); > } > }; > > module.exports = ListStore; > ~~~ 上面代码中,`ListStore.items`用来保存条目,`ListStore.getAll()`用来读取所有条目,`ListStore.emitChange()`用来发出一个"change"事件。 由于 Store 需要在变动后向 View 发送"change"事件,因此它必须实现事件接口。 > ~~~ > // stores/ListStore.js > var EventEmitter = require('events').EventEmitter; > var assign = require('object-assign'); > > var ListStore = assign({}, EventEmitter.prototype, { > items: [], > > getAll: function () { > return this.items; > }, > > addNewItemHandler: function (text) { > this.items.push(text); > }, > > emitChange: function () { > this.emit('change'); > }, > > addChangeListener: function(callback) { > this.on('change', callback); > }, > > removeChangeListener: function(callback) { > this.removeListener('change', callback); > } > }); > ~~~ 上面代码中,`ListStore`继承了`EventEmitter.prototype`,因此就能使用`ListStore.on()`和`ListStore.emit()`,来监听和触发事件了。 Store 更新后(`this.addNewItemHandler()`)发出事件(`this.emitChange()`),表明状态已经改变。 View 监听到这个事件,就可以查询新的状态,更新页面了。
    ';

    六、Dispatcher

    最后更新于:2022-04-01 22:36:19

    ## 六、Dispatcher Dispatcher 的作用是将 Action 派发到 Store、。你可以把它看作一个路由器,负责在 View 和 Store 之间,建立 Action 的正确传递路线。注意,Dispatcher 只能有一个,而且是全局的。 Facebook官方的 [Dispatcher 实现](https://github.com/facebook/flux)输出一个类,你要写一个[`AppDispatcher.js`](https://github.com/ruanyf/extremely-simple-flux-demo/blob/master/dispatcher/AppDispatcher.js),生成 Dispatcher 实例。 > ~~~ > // dispatcher/AppDispatcher.js > var Dispatcher = require('flux').Dispatcher; > module.exports = new Dispatcher(); > ~~~ `AppDispatcher.register()`方法用来登记各种Action的回调函数。 > ~~~ > // dispatcher/AppDispatcher.js > var ListStore = require('../stores/ListStore'); > > AppDispatcher.register(function (action) { > switch(action.actionType) { > case 'ADD_NEW_ITEM': > ListStore.addNewItemHandler(action.text); > ListStore.emitChange(); > break; > default: > // no op > } > }) > ~~~ 上面代码中,Dispatcher收到`ADD_NEW_ITEM`动作,就会执行回调函数,对`ListStore`进行操作。 记住,Dispatcher 只用来派发 Action,不应该有其他逻辑。
    ';

    五、Action

    最后更新于:2022-04-01 22:36:17

    ## 五、Action 每个Action都是一个对象,包含一个`actionType`属性(说明动作的类型)和一些其他属性(用来传递数据)。 在这个Demo里面,[`ButtonActions`](https://github.com/ruanyf/extremely-simple-flux-demo/blob/master/actions/ButtonActions.js) 对象用于存放所有的Action。 > ~~~ > // actions/ButtonActions.js > var AppDispatcher = require('../dispatcher/AppDispatcher'); > > var ButtonActions = { > addNewItem: function (text) { > AppDispatcher.dispatch({ > actionType: 'ADD_NEW_ITEM', > text: text > }); > }, > }; > ~~~ 上面代码中,`ButtonActions.addNewItem`方法使用`AppDispatcher`,把动作`ADD_NEW_ITEM`派发到Store。
    ';

    四、View(第一部分)

    最后更新于:2022-04-01 22:36:15

    ## 四、View(第一部分) 请打开 Demo 的首页[`index.jsx`](https://github.com/ruanyf/extremely-simple-flux-demo/blob/master/index.jsx) ,你会看到只加载了一个组件。 > ~~~ > // index.jsx > var React = require('react'); > var ReactDOM = require('react-dom'); > var MyButtonController = require('./components/MyButtonController'); > > ReactDOM.render( > , > document.querySelector('#example') > ); > ~~~ 上面代码中,你可能注意到了,组件的名字不是 `MyButton`,而是 `MyButtonController`。这是为什么? 这里,我采用的是 React 的 [controller view](http://blog.andrewray.me/the-reactjs-controller-view-pattern/) 模式。"controller view"组件只用来保存状态,然后将其转发给子组件。`MyButtonController`的[源码](https://github.com/ruanyf/extremely-simple-flux-demo/blob/master/components/MyButtonController.jsx)很简单。 > ~~~ > // components/MyButtonController.jsx > var React = require('react'); > var ButtonActions = require('../actions/ButtonActions'); > var MyButton = require('./MyButton'); > > var MyButtonController = React.createClass({ > createNewItem: function (event) { > ButtonActions.addNewItem('new item'); > }, > > render: function() { > return onClick={this.createNewItem} > />; > } > }); > > module.exports = MyButtonController; > ~~~ 上面代码中,`MyButtonController`将参数传给子组件`MyButton`。后者的[源码](https://github.com/ruanyf/extremely-simple-flux-demo/blob/master/components/MyButton.jsx)甚至更简单。 > ~~~ > // components/MyButton.jsx > var React = require('react'); > > var MyButton = function(props) { > return
    > >
    ; > }; > > module.exports = MyButton; > ~~~ 上面代码中,你可以看到[`MyButton`](https://github.com/ruanyf/extremely-simple-flux-demo/blob/master/components/MyButton.jsx)是一个纯组件(即不含有任何状态),从而方便了测试和复用。这就是"controll view"模式的最大优点。 `MyButton`只有一个逻辑,就是一旦用户点击,就调用[`this.createNewItem`](https://github.com/ruanyf/extremely-simple-flux-demo/blob/master/components/MyButtonController.jsx#L27) 方法,向Dispatcher发出一个Action。 > ~~~ > // components/MyButtonController.jsx > > // ... > createNewItem: function (event) { > ButtonActions.addNewItem('new item'); > } > ~~~ 上面代码中,调用`createNewItem`方法,会触发名为`addNewItem`的Action。
    ';

    三、基本概念

    最后更新于:2022-04-01 22:36:13

    ## 三、基本概念 讲解代码之前,你需要知道一些 Flux 的基本概念。 首先,Flux将一个应用分成四个部分。 > * View: 视图层 > * Action(动作):视图层发出的消息(比如mouseClick) > * Dispatcher(派发器):用来接收Actions、执行回调函数 > * Store(数据层):用来存放应用的状态,一旦发生变动,就提醒Views要更新页面 ![](http://www.ruanyifeng.com/blogimg/asset/2016/bg2016011503.png) Flux 的最大特点,就是数据的"单向流动"。 > 1. 用户访问 View > 2. View 发出用户的 Action > 3. Dispatcher 收到 Action,要求 Store 进行相应的更新 > 4. Store 更新后,发出一个"change"事件 > 5. View 收到"change"事件后,更新页面 上面过程中,数据总是"单向流动",任何相邻的部分都不会发生数据的"双向流动"。这保证了流程的清晰。 读到这里,你可能感到一头雾水,OK,这是正常的。接下来,我会详细讲解每一步。
    ';

    二、安装 Demo

    最后更新于:2022-04-01 22:36:10

    ## 二、安装 Demo 为了便于讲解,我写了一个[Demo](https://github.com/ruanyf/extremely-simple-flux-demo)。 请先安装一下。 > ~~~ > $ git clone https://github.com/ruanyf/extremely-simple-flux-demo.git > $ cd extremely-simple-flux-demo && npm install > $ npm start > ~~~ 然后,访问 http://127.0.0.1:8080 。 ![](http://www.ruanyifeng.com/blogimg/asset/2016/bg2016011502.png) 你会看到一个按钮。这就是我们的Demo。
    ';

    一、Flux 是什么?

    最后更新于:2022-04-01 22:36:08

    ## 一、Flux 是什么? 简单说,Flux 是一种架构思想,专门解决软件的结构问题。它跟[MVC 架构](http://www.ruanyifeng.com/blog/2007/11/mvc.html)是同一类东西,但是更加[简单和清晰](http://www.infoq.com/news/2014/05/facebook-mvc-flux)。 Flux存在多种实现([至少15种](https://github.com/voronianski/flux-comparison)),本文采用的是[Facebook官方实现](https://github.com/facebook/flux)。
    ';

    前言

    最后更新于:2022-04-01 22:36:06

    > 出处:[阮一峰的博客](http://www.ruanyifeng.com/blog/2016/01/flux.html) > 作者:阮一峰 过去一年中,前端技术大发展,最耀眼的明星就是[React](https://facebook.github.io/react/)。 React 本身只涉及UI层,如果搭建大型应用,必须搭配一个前端框架。也就是说,你至少要学两样东西,才能基本满足需要:React + 前端框架。 Facebook官方使用的是 [Flux 框架](https://facebook.github.io/flux/)。本文就介绍如何在 React 的基础上,使用 Flux 组织代码和安排内部逻辑,使得你的应用更易于开发和维护。 ![](http://www.ruanyifeng.com/blogimg/asset/2016/bg2016011501.png) 阅读本文之前,我假设你已经掌握了 React 。如果还没有,可以先看我写的[《React入门教程》](http://www.ruanyifeng.com/blog/2015/03/react.html)(注:[看云阅读版本点击这里](http://www.kancloud.cn/kancloud/react/67574))。与以前一样,本文的目标是使用最简单的语言、最好懂的例子,让你一看就会。
    ';