@cjy0208/redux-module

Make Redux more like vuex

Usage no npm install needed!

<script type="module">
  import cjy0208ReduxModule from 'https://cdn.skypack.dev/@cjy0208/redux-module';
</script>

README

redux-module

一个让 redux 写起来像 vuex 一样简单的轮子

使用方法

// ......
// module.js
import { createModule } from '@cjy0208/redux-module'

const delay = time => new Promise(resolve => setTimeout(resolve, time))

const reduxModule = createModule({
  name: 'main',
  state: {
    counter: 0,
    text: ''
  },
  actions: ({
    commit, // commit 为原 redux 的 dispatch
    dispatch, // dispatch 只触发到动作层
    getState, // 获取当前 module 的 state
    getReduxState, // 获取整个 redux store 的 state
    getModules // 获取其他 module 以进行模块间通信
  }) => ({
    counter: {
      add: (amount = 1) => commit('add', amount),
      reduce: (amount = 1) => commit('reduce', -1 * amount)
    },
    // 将异步控制从 redux 中拆离,异步操作不依赖其他中间件
    text: async text => {
      await delay(1000)
      commit('text', text)
      await delay(2000)
      commit('add', 1) // 同一个 action 可以 commit 多次
    }
  }),
  mutations: ({ combine }) => ({
    // 变化响应可以合并,类似 redux-actions 的 combineActions
    [combine('add', 'reduce')]: ({ counter }, amount) => ({
      counter: counter + amount
    }),
    text: (state, text) => ({ text })
  }),
  // 允许衍生状态
  getters: {
    text: state => `computed::${state.text}`
  }
})

export default reduxModule

// ......
// store.js
import { createStore, applyMiddleware, compose, combineReducers } from 'redux'
import reduxModule from './module.js'

const store = createStore(reduxModule.reducer)

export default store

// ......
// app.js
import React, { Component } from 'react'
import { connectModules } from '@cjy0208/redux-module'

@connectModules(({ main }) => ({
  main
}))
export default class App extends Component {
  render() {
    const { main } = this.props

    return (
      <div>
        Home
        <div>
          module counter is: {main.state.counter}
          <button onClick={() => main.dispatch('counter/add')}>add</button>
          <button onClick={() => main.dispatch('counter/reduce')}>
            reduce
          </button>
        </div>
        
        <input onChange={e => {
          const value = e.target.value
          main.commit('text', value) // 允许直接 commit
        }} />
        <input onChange={e => {
          const value = e.target.value
          main.dispatch('text', value)
        }} />
        <div>main text is: {main.state.text}</div>
        <div>main getters.text is: {main.getters.text}</div>
      </div>
    )
  }
}

// ......
// index.js
import React from 'react'
import { render } from 'react-dom'
import { ModuleProvider } from '@cjy0208/redux-module'
import App from './app.js'
import store from './store'

render(
  <ModuleProvider {...{ store }}>
    <App />
  </ModuleProvider>,
  document.getElementById('app')
)