UNPKG

yax

Version:

Yet another store using redux. (Inspired by vuex and dva)

140 lines (122 loc) 3.8 kB
import { createStore, applyMiddleware, compose } from 'redux'; import ModuleCollection from './module/module-collection'; import { isObject, isPromise, getNestedState, assert } from './util'; export default function yax (options = {}, enhancer) { let _actions = {}; const _modules = new ModuleCollection(options); // init root module. // this also recursively registers all sub-modules _installModule([], _modules.root); const middleware = () => (next) => (action) => { if (isObject(action)) { const { type, payload } = action; const entry = _actions[type]; if (entry) { return entry.length > 1 ? Promise.all(entry.map(handler => handler(payload))) : entry[0](payload); } } return next(action); }; const rootMW = applyMiddleware(middleware); const _store = createStore( _modules.makeReducers(), options.state || {}, enhancer ? compose(enhancer, rootMW) : rootMW ); function registerModule (path, rawModule) { if (typeof path === 'string') path = [path]; assert(Array.isArray(path), `module path must be a string or an Array.`); _modules.register(path, rawModule); _installModule(path, _modules.get(path)); _resetReducers(); } function unregisterModule (path) { if (typeof path === 'string') path = [path]; assert(Array.isArray(path), `module path must be a string or an Array.`); _modules.unregister(path); _resetStore(); _store.dispatch({ type: '@@yax/unregister', path }); } return { registerModule, unregisterModule, ..._store }; /** * Private Methods */ // make localized dispatch, commit and state function _makeLocalContext (namespace, path) { const wrapFn = (type, payload, isRoot) => { let action = { type, payload }; if (isObject(type) && type.type) { isRoot = payload; action = type; } action.type = isRoot ? action.type : namespace + action.type; // redux dispatch return _store.dispatch(action); }; const local = { dispatch: wrapFn, commit: wrapFn, select: (fn) => { // redux state const rootState = _store.getState(); const state = getNestedState(rootState, path); return fn ? fn(state, rootState) : state; } }; return local; } function _registerAction (type, handler, local) { const entry = _actions[type] || (_actions[type] = []); entry.push(function wrappedActionHandler (payload) { let res = handler({ dispatch: local.dispatch, commit: local.commit, select: local.select }, payload); if (!isPromise(res)) { res = Promise.resolve(res); } return res; }); } function _installModule (path, module) { const namespace = _modules.getNamespace(path); const local = module.context = _makeLocalContext(namespace, path); module.cleanReducers(); module.forEachReducer((reducer, key) => { const actionType = namespace + key; module.addReducer(actionType, reducer); }); module.forEachAction((action, key) => { const actionType = namespace + key; _registerAction(actionType, action, local); }); module.forEachChild((child, key) => { _installModule(path.concat(key), child); }); } function _resetReducers () { const reducer = _modules.makeReducers(); _store.replaceReducer(reducer); } function _resetStore () { _actions = {}; // init all modules _installModule([], _modules.root); _resetReducers(); } } export { combineReducers, bindActionCreators, applyMiddleware, compose } from 'redux'; export { composeReducers, mapReducers } from './util'; export { mapState, mapActions } from './helpers';