reflux使用

867 阅读4分钟

安装:

npm install reflux

引入:

var Reflux = require("reflux");//CommonJS风格 commonjs导出的话 需要使用 module.exports=导出定义的名字

import Reflux from "reflux";//ES6风格

Reflux的主要功能是引入一个函数式编程风格架构,采用单向数据流模式,而非MVC类似的模式。

这个模式由actions和data stores组成。当actions引入新数据时,要经过data stores之后再由view 组件展示。如果组件有事件要更改data stores,也需要经过相应的actions再传递到stores。

要用reflux,我们需要创建可以被React Component唤起的actions;负责存储、更新数据的stores,stores会监听actions;同样的,stores会与React Component挂钩 ,当store里state更新时,也更新React Component中的state。因此,有3个概念如下:

1、创建actions

2、创建stores

3、创建 stores与React Component的联系(钩子)

一个Reflux应用只包含3个部分: Action,负责消息的分发,一般是由用户行为触发 Store,负责监听Action的触发,也负责通知View更新UI View,负责监听Store的数据变化,在Store数据变化之后,会自上而下完成一次渲染(re-render)

此时会有人问:没有了消息中枢(Dispatcher),消息Actions如何发布出去,并传递到Stores呢?

答:在Reflux中,每一个Action本身就是一个Publisher(消息发布者),即自带了消息发布功能;而每一个Store除了作为数据存储之外,它还是一个Subscriber,或者叫做Listener(消息订阅者),自然就可以通过监听Action,来获取到变化的数据。

一般说来,在实际项目代码中,由于涉及到的Action较多,所以一般都是调用Reflux.createActions()一次性创建Actions集合,比较方便。另外,之后Store通过listenables字段与Action进行关联时,需要的也是一个Actions集合。

Reflux单向数据流的实现,是完全基于PubSub设计模式的。 Action,Store和View三者的角色分配以及分工合作,如下: Action 是一个Publisher,负责消息的分发,一般是由用户行为(User Interaction),或是Web API触发。

Store 不仅是一个Publisher,还是一个Subscriber(或者叫做Listener),作为Subscriber,负责监听Action的触发;作为Publisher,则负责通知View更新UI。

View 是一个Subscriber,负责监听Store的数据变化,做到及时更新UI。 在Reflux中,因为没有了Action Creator的概念,所以,Action的创建都是通过统一的API:Reflux.createAction()或者Reflux.createActions()来实现。

答:Reflux抽取出两个模块:PublisherMethods 和 ListenerMethods,顾名思义,这两个集合分别存储着一个对象作为Publisher和Listener所应该具有的方法。

比如:

PublisherMethods(时间抛发)中包括:trigger、triggerAsync等消息发布方法。

ListenerMethods(事件更新和侦听)中就包括listenTo、listenToMany等消息订阅方法。

// 拥有配置
var action = Reflux.createAction({
    actionName: 'addItem',  // 其实这个actionName并没有什么用,可不传
    asyncResult: true,
    sync: false,
    children: ['success']
});
 
// 简化
var action = Reflux.createAction('addItem')
 
// 或者匿名
var addItemAction = Reflux.createAction();

sync: 设置为true,指定action的默认触发方式为 同步 children: 用于创建子Action(主要是用在异步操作的时候,后面会讲到) asyncResult:设置为true时,自动创建两个名为'completed'和'failed'的子Action(可以认为是设置子Action的一个快捷方式)

2.通过Reflux.createActions()创建多个Action,即Actions集合,代码如下


var actions = Reflux.createActions(['addItem', 'deleteItem']);
 
// 个别action配置
var actions = Reflux.createActions(['addItem', {
    deleteItem: {
        asyncResult: true,
        children: ['success'],
    },
    updateItem: {...}
}]);
 
// 也可以这样
var actions = Reflux.createActions({
    addItem: {},
    deleteItem: {
        asyncResult: true,
        children: ['success']
    },
    updateItem: {...}

注意:Reflux.createActions()返回的是一个普通的对象,即Actions集合,所以Action触发时,需要指定actionName,就像这样:

    actions.addItem({...});
    actions.deleteItem();

一般说来,在实际项目代码中,由于涉及到的Action较多,所以一般都是调用Reflux.createActions()一次性创建Actions集合,比较方便。另外,之后Store通过listenables字段与Action进行关联时,需要的也是一个Actions集合。

之前就提到,Action作为一个Publisher,会拥有PublisherMethods集合里提供的一系列方法,这里统一举例说明 listen:Action消息订阅

var addAction = Reflux.createAction();
     
    addAction.listen(function (url) {
        // 默认上下文this是addAction
        $.ajax(url).done(function () {
            // todo: save to store
        });
    });
     
    addAction('/xxx/add');

rigger 同步触发Action消息,在触发具体的消息之前,首先会先执行preEmit和shouldEmit回调。

preEmit返回值(非undefined)将作为shouldEmit函数的入参,用于修改payload shouldEmit的返回值(true or false),将作为是否真正触发消息的标志

preEmit用于异步请求,下面两种方法是等价的

    var actions = Reflux.createActions({
    add: {
        asyncResult: true,
        preEmit: function (url) {
            $.ajax(url)
                .done(this.completed)
                .fail(this.failed);
        }
    }
});
 
// 等价于
 
var actions = Reflux.createActions({
    add: {
        asyncResult: true
    }
});
 
actions.add.listen(function(url) {
    $.ajax(url)
        .done(this.completed)
        .fail(this.failed)
});

preEmit用于修改payload


var actions = Reflux.createActions(['takePhoto']);
 
// 映射
var maps = {
    'photo': {
        maxSize: 1000     // 从相册获取
    },
    'camera': {           // 拍照
        maxSize: 2000,
        maxSelect: 10
    }
};
 
actions.takePhoto.preEmit = function (type) {
    return maps[type] || maps['photo'];
};
 
actions.takePhoto.listen(function (options) {
    // do ajax
    console.log(options);
});
 
actions.takePhoto('photo');
// 或者

shouldEmit的使用(防止action的频繁触发)

var requesting = false;
var actions = Reflux.createActions(['submit']);
 
actions.submit.shouldEmit = function () {
    return !requesting;
}
 
actions.submit.listen(function (url) {
 
    requesting = true;
    
    $.ajax(url).done(function () {
        // success
    }).fail(function () {
        // error
    }).always(function () {
        requesting = false;
    });
});
 
// 点击按钮
$('#btn').click(function () {
    actions.submit('url/submit');
});

romise: 语法糖,用于简写异步Action,下面两种方法是等价的:

var addAction = Reflux.createAction({
    children: ['completed', 'failed'] // 等价于 asyncResult: true
});
 
addAction.listen(function (url) {
    var me = this;
    $.ajax(url).done(function (data) {
        me.completed(data);
    }).fail(function () {
        me.failed();
    });
});
 
// 等价于
addAction.listen(function (url) {
    this.promise($.ajax(url));
});
 
addAction('/url/add');

listenAndPromise: 是上述两个方法listen和promise方法的结合,做了两件事情:消息订阅和异步回调。 比如上面的例子,就可以这样简写

addAction.listenAndPromise(function(url) {
    return $.ajax(url);    // 注意:返回promise对象
});

riggerAsync: 异步触发Action消息(而trigger同步触发消息),类似于

setTimeout(function () {action();}, 0)

triggerPromise 触发Action消息,可以通过返回的promise将异步请求的数据直接带回,而不需要经过Store。


var addAction = Reflux.createAction({
    asyncResult: true
});
 
addAction.listenAndPromise(function(url) {
    return $.ajax(url);    // 注意:返回promise对象
});
 
// 触发消息,监听异步子action的成功与失败
// action这里可以获取到数据,
addAction.triggerPromise('/url/add').then(function (data) {
    console.log(data);
}, function () {
    console.log('failed');
});