ngDva

最近在ng4上面用redux,感觉redux原生的Reducer写法还是太麻烦了。写了一个function生成。还加入co用于 Generator 函数的自动执行和全局store修改。还有日志功能,输出action.type,action.payload,当前Reducer的参数即model的状态,全局的store(用于修改其它Reducer/model中的状态)。

import co from 'co';
import * as warning from 'warning';

const SEP = '/'
function run(model: any, store, log) {
    const { namespace, effects } = model;
    warning(namespace != null, `namespace is a must`);
    warning(effects != null, `effects is a must`);
    function applyNamespace(type) {
        function getNamespacedReducers(reducers) {
            return Object.keys(reducers).reduce((memo, key) => {
                warning(
                    key.indexOf(`${namespace}${SEP}`) !== 0,
                    `app.model: ${type.slice(0, -1)} ${key} should not be prefixed with namespace ${namespace}`,
                );
                memo[`${namespace}${SEP}${key}`] = reducers[key];
                return memo;
            }, {});
        }

        if (model[type]) {
            if (type === 'effects') {

                model[type] = getNamespacedReducers(model[type]);

            }
        }
    }

    applyNamespace('effects');
    Object.defineProperty(model, 'namespace', { enumerable: false, writable: false, configurable: false })
    Object.defineProperty(model, 'effects', { enumerable: false, writable: false, configurable: false })

    // for(var x in model){
    //     debugger;
    // }
    function res(state = model.state, action) {

        for (var key in model.effects) {
            if (action.type == key) {
                co(model.effects[key].bind(state, action, store)).then((val) => {
                    if (action.callback != null) {
                        action.callback(val)
                    }
                    if (process.env.node_ENV != 'production') {
                        if (log) {
                            console.group("dispatch log");
                            console.log("action type:",action.type);
                            console.log("action payload:",action.payload);
                            console.log("current state:",state);
                            console.log("global store:",store);
                            console.groupEnd();
                        }
                    }
                }, (e) => { console.error(e.stack); })

                return state
            }
        }
        return state;
    }
    return res
}

function dva(models, log = false) {

    let store = {};
    let root = {}
    models.forEach((x) => {

        root[x.namespace] = x.state;
        store[x.namespace] = run(x, root, log);
    });
    return store;
}
export default dva;

使用:

const data = {
    namespace: 'data',

    state: {
        cout:0
    },

    effects: {
        *INCREMENT({payload}) {
            var data=yield new Promise(function(resolve, reject) {
                    setTimeout(()=>{
                        resolve(2)
                    },1000)
                });

            this.cout += data;
        },
        *DECREMENT({payload},store) {
            this.cout -= 1;
         //   console.log(store);
         //   setTimeout(()=>{store.data.state+=1;},1000)
         //   store.data.state-=1;
        },
        *RESET({payload}) {
            this.cout = 0;
        }
    }
}

StoreModule.provideStore(dva([data],true)),