179 lines
4.2 KiB
JavaScript
179 lines
4.2 KiB
JavaScript
import { createAction, handleActions } from 'redux-actions'
|
|
import { fromJS } from 'immutable'
|
|
import {thunkAction} from '../../utils/common'
|
|
|
|
export class ReduxModule {
|
|
|
|
constructor () {
|
|
this._namespace = this.getNamespace()
|
|
this._actions = {}
|
|
this._reducers = {}
|
|
}
|
|
|
|
init () {
|
|
this._initialState = fromJS(this.getInitialState())
|
|
const actions = this.defineActions()
|
|
const reducers = this._addNamespaceToReducers(this.defineReducers())
|
|
Object.assign(this._actions, actions)
|
|
Object.assign(this._reducers, reducers)
|
|
this.reducers = handleActions(this._reducers, this._initialState)
|
|
this.actions = this._actions
|
|
}
|
|
|
|
getNamespace () {
|
|
//implement in subclasses
|
|
}
|
|
|
|
getInitialState () {
|
|
//implement in subclasses
|
|
}
|
|
|
|
defineActions () {
|
|
//implement in subclasses
|
|
//it should return hash of function
|
|
/**
|
|
* return {
|
|
* action1,
|
|
* action2
|
|
* }
|
|
*/
|
|
}
|
|
|
|
defineReducers () {
|
|
//implement in subclasses
|
|
/*
|
|
return {
|
|
[actionName]: this.****Reducer()
|
|
}
|
|
or use this.addReducer()
|
|
*/
|
|
}
|
|
|
|
_addNamespaceToReducers (obj) {
|
|
const result = {}
|
|
for (let actionName in obj) {
|
|
result[this.ns(actionName)] = obj[actionName]
|
|
}
|
|
return result
|
|
}
|
|
|
|
/** utils **/
|
|
ns (actionName) {
|
|
return `${this._namespace} ${actionName}`
|
|
}
|
|
|
|
evalPath (path) {
|
|
return path
|
|
//TODO: something better
|
|
/*return path.map(
|
|
(item) => (typeof item === 'function') ? item(state) : item
|
|
);*/
|
|
}
|
|
|
|
/** action creators **/
|
|
createAction (actionName, actionFn) {
|
|
return createAction(this.ns(actionName), actionFn)
|
|
}
|
|
|
|
thunkAction (actionName, actionMethod, emitPending) {
|
|
return thunkAction(this.ns(actionName), actionMethod, emitPending)
|
|
}
|
|
|
|
thunkPendingReducer (field) {
|
|
return (state, {payload: {isPending}}) => state.set(field, isPending)
|
|
}
|
|
|
|
/** reducer creators **/
|
|
setReducer (field) {
|
|
return (state, {payload: value}) => state.set(field, value)
|
|
}
|
|
|
|
setInReducer (path) {
|
|
return (state, {payload: value}) => state.setIn(this.evalPath(path), value)
|
|
}
|
|
|
|
setFieldReducer () {
|
|
return (state, {payload: {field, value}}) => state.set(field, value)
|
|
}
|
|
|
|
resetReducer (field, defaultValue) {
|
|
return (state) => state.set(field, defaultValue)
|
|
}
|
|
|
|
mergeReducer () {
|
|
return (state, {payload: values}) => state.merge(values)
|
|
}
|
|
|
|
mergeInReducer (path) {
|
|
return (state, {payload: values}) => state.mergeIn(this.evalPath(path), values)
|
|
}
|
|
|
|
toggleReducer (field) {
|
|
return (state) => state.set(field, !state.get(field))
|
|
}
|
|
|
|
toggleInReducer (path) {
|
|
return (state) => {
|
|
const realPath = this.evalPath(path)
|
|
return state.setIn(realPath, !state.getIn(realPath))
|
|
}
|
|
}
|
|
|
|
addReducer (actionName, reducerFn) {
|
|
this._reducers[this.ns(actionName)] = reducerFn
|
|
}
|
|
|
|
//do not prefix with namespace
|
|
addExternalReducer (actionName, reducerFn) {
|
|
this._reducers[actionName] = reducerFn
|
|
}
|
|
|
|
/** handler creators
|
|
* handler = action + reducer
|
|
**/
|
|
createHandler (actionName, actionFn, reducerFn) {
|
|
const action = this.createAction(actionName, actionFn)
|
|
this.addReducer(actionName, reducerFn)
|
|
return action
|
|
}
|
|
|
|
set (actionName, field) {
|
|
return this.createHandler(actionName, {}, this.setReducer(field))
|
|
}
|
|
|
|
setIn (actionName, path) {
|
|
return this.createHandler(actionName, {}, this.setInReducer(path))
|
|
}
|
|
|
|
setField (actionName) {
|
|
return this.createHandler(actionName, (field, value) => ({field, value}), this.setFieldReducer())
|
|
}
|
|
|
|
reset (actionName, field, defaultValue) {
|
|
return this.createHandler(actionName, {}, this.resetReducer(field, defaultValue))
|
|
}
|
|
|
|
merge (actionName) {
|
|
return this.createHandler(actionName, {}, this.mergeReducer())
|
|
}
|
|
|
|
mergeIn (actionName, path) {
|
|
return this.createHandler(actionName, {}, this.mergeInReducer(path))
|
|
}
|
|
|
|
toggle (actionName, field) {
|
|
return this.createHandler(actionName, {}, this.toggleReducer(field))
|
|
}
|
|
|
|
toggleIn (actionName, path) {
|
|
return this.createHandler(actionName, {}, this.toggleInReducer(path))
|
|
}
|
|
|
|
resetToInitialState (actionName) {
|
|
return this.createHandler(actionName, {}, () => this._initialState)
|
|
}
|
|
|
|
}
|
|
|
|
export default ReduxModule
|