Skip to content

Instantly share code, notes, and snippets.

@lovetingyuan
Created November 14, 2020 04:11
Show Gist options
  • Save lovetingyuan/145a90bf7fa174214f9cf07cd6aa5237 to your computer and use it in GitHub Desktop.
Save lovetingyuan/145a90bf7fa174214f9cf07cd6aa5237 to your computer and use it in GitHub Desktop.
combine redux and immer
import { createStore, combineReducers, compose, applyMiddleware } from 'redux'
import produce from 'immer'
function init (model, middleware) {
const reducers = {}
const root = Object.create({
get store () { return store },
get state () { return store.getState() }
})
Object.entries(model).forEach(([name, option]) => {
if (name === 'store' || name === 'state') {
throw new Error('You can not use "store" or "state" as module name.')
}
const initState = {}
const reducerMap = root[name] = {}
Object.entries(option).forEach(([key, val]) => {
if (typeof val === 'function') {
reducerMap[key] = payload => {
store.dispatch({ type: `${name}/${key}`, payload })
}
} else {
initState[key] = val
}
})
reducers[name] = ({
[name](state, action) {
const [moduleName, reducerName] = action.type.split('/')
if (!(moduleName in model)) return initState
if (moduleName !== name) return state
const reducer = model[moduleName][reducerName]
return produce(state, draft => reducer.call(draft, action.payload))
}
})[name]
})
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
if (!Array.isArray(middleware)) {
middleware = []
}
const store = createStore(
combineReducers(reducers),
composeEnhancers(
applyMiddleware(...middleware)
)
)
return root
}
@lovetingyuan
Copy link
Author

const foo = {
  name: 'foo',
  setName(newName) {
    this.name = newName
  }
}

const bar = {
  age: 12,
  growUp() {
    this.age++
  }
}

const store = init({ foo, bar })

store.foo.setName('tingyuan') // store.state.foo.name === 'tingyuan'
store.bar.growUp() // store.state.bar.age === 13

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment