谈谈Flux

2016-03-21 Alex Sun 更多博文 » 博客 » GitHub »

原文链接 https://syaning.github.io/2016/03/21/flux/
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。


参考资料

1. 什么是Flux

首先,Flux是一种应用架构,是一种模式,而不是一个框架。它有着多种实现。例如Facebook官方实现Redux等。

2. 为什么要使用Flux

Flux的出现主要是为了解决应用的状态维护问题。在小型项目中,Model和View可能是一一对应的关系,维护起来并不困难。但是随着应用规模的扩大,Model和View通常是多对多的关系,每一个Model的改变,和它相关的View都要改变;每个View的操作,也都要反映到它相关的Model上。在这种情况下,状态的维护会变得复杂和混乱。

3. Flux的基本结构

Flux的基本结构如图:

Flux Diagram

图片来源:https://github.com/facebook/flux

简化结构如下:

Flx Simple Diagram

图片来源:https://facebook.github.io/flux/docs/overview.html#content

首先,可以看到Flux的一个特点是单向数据流

Flux的基本组成包括:

  • View
  • Action
  • Dispatcher
  • Store

它们的功能和关系是:

  • View负责展示给用户
  • 用户与View的交互会发出Action,例如click操作
  • Dispatcher收到Action后进行派发给相应的Store
  • Store更新数据,发出change事件
  • View接收到change事件,更新界面

4. 如何使用

下面通过一个非常简单的例子来介绍Flux的基本使用。

(1) Dispatcher

Dispatcher的创建非常简单:

var Dispatcher = require('flux').Dispatcher;

module.exports = new Dispatcher();

(2) Action

Action就是一个普通的对象,在Action中通过dispatcher.dispatch(payload)来分发事件。每个payload有一个type(或类似的名称)属性来表示Action的类型,此外可以有其它的属性来传递该Action所相关的数据。

const dispatcher = require('./dispatcher')

var actions = {
    addItem: function(text) {
        dispatcher.dispatch({
            type: 'add',
            text
        })
    }
}

module.exports = actions

(3) Store

Store用来存放数据模型。通过事件系统(这里使用的是Node的EventEmitter,也可以使用其它的实现)可以发出和接收事件。

通过dispatcher.register(callback)来注册回调函数,从而当Dispatcher接收到Action的时候,会通知Store来更新数据。

当Store更新后,要发出change事件。

const EventEmitter = require('events').EventEmitter
const dispatcher = require('./dispatcher')

var items = []
var store = Object.create(EventEmitter.prototype, {
    items: {
        get: function() {
            return items
        }
    }
})

function addItem(text) {
    items.push(text)
}

dispatcher.register(function(action) {
    switch (action.type) {
        case 'add':
            addItem(action.text)
            store.emit('change')
            break
        default:
            break
    }
})

module.exports = store

(4) View

View就是React的组件了。用户的交互会通过Action发出事件。

const React = require('react')
const store = require('./store')
const action = require('./action')

class App extends React.Component {
    constructor(props) {
        // ...
    }

    componentDidMount() {
        store.on('change', this.onItemsChange.bind(this))
    }

    componentWillUnmount() {
        store.removeListener('change', this.onItemsChange.bind(this))
    }

    onItemsChange() {
        // ...
    }

    // ...

    addItem() {
        action.addItem(this.state.value)
        // ...
    }

    render() {
        // ...
    }
}

module.exports = App

5. 注意点

  • 只有一个全局的Dispatcher
  • Action用来描述做什么事,通过dispatcher.dispatch(payload)来分发事件,不涉及具体的数据逻辑
  • Store不是Model,Store内存放着Model
  • 如果应用规模较大,可以根据应用模块来分成多个Store
  • 只有Store才可以通过dispatcher.register(callback)来注册回调函数