1.5.0 • Published 4 years ago

redux-effect-models v1.5.0

Weekly downloads
3
License
MIT
Repository
github
Last release
4 years ago

redux-effect-models

build status code style: prettier Coverage Status npm version License: MIT

如果你使用过 dva 或者 vuex 很容易就能理解这是什么。

此插件没有改变 redux,只是提供了一种不同于官方推荐的数据流构建方式。

采用了以 Model 为单位,将数据分割成多个模块进行管理,每个 Model 负责管理好自己的内部状态,降低了数据流管理的复杂度。

  • 支持 Typescript
  • 支持 异步 Action
  • 支持 中间件
  • 支持 动态添加 Model

安装

$ yarn add redux-effect-models

或者

$ npm i redux-effect-models

使用

  1. 创建一个最简单的 Model
// src/store/models/counter.js
export default {
  namespace: 'counter',
  state: {
    count: 0,
  },
  effects: {
    async addCount(context, action) {
      await context.delay(300);
      context.dispatch({
        type: 'saveCount',
        payload: context.state.count + action.payload
      })
    }
  },
  reducers: {
    saveCount(state, action) {
      return {
        ...state,
        count: action.payload,
      };
    },
  },
}
  1. 调用 reduxEffectModels 初始化状态
// src/store/models/index.js
import { reduxEffectModels } from 'redux-effect-models';
import counter from './counter';

const { reducer, state, effect } = reduxEffectModels([counter]);

export { 
  // Redux Reducer
  reducer, 
  // 所有 `Model State` 合并出的初始状态
  state,
  // Redux Middleware
  effect
}
  1. 创建 Redux Store 时, 将调用 reduxEffectModels 返回的 reducer state effect 传入 createStore
// src/store/index.js
import { createStore, applyMiddleware } from 'redux';
import { reducer, state, effect } from './models';

const store = createStore(reducer, state, applyMiddleware(effect));

export default store;
  1. 修改 store 中的状态,action type 就是 Modelnamespace + / + key
// xxx.js
import store from './store';

console.log(store.getState().counter.count) // 0

// 触发一个 reducer
store.dispatch({
  type: 'counter/saveCount',
  payload: 100,
});
console.log(store.getState().counter.count) // 这个时候 counter 中的 count 等于 100

// 触发一个 effect 会返回一个 Promise
const p = store.dispatch({
  type: 'counter/addCount',
  payload: 100,
}); 

p.then(() => {
  console.log(store.getState().counter.count) // 这个时候 counter 中的 count 等于 200
})

概念

Model

Model 完整结构如下所示

{
  namespace:   string;                           // 用于识别当前 Model
  state:       { [key: string]: any };           // 用于合并 rootState
  middlewares?: { [key: string]: Middleware[] }; // 用于处理通用异步逻辑
  effects?:     { [key: string]: Effect };       // 用于处理异步逻辑
  reducers:    { [key: string]: Reducer };       // 用于同步修改状态
}

Reducer

类型: (state, action) => Object

Reducer 必须是一个纯函数, 修改状态的唯一方式是提交一个 Reducer, 接收 stateaction 两个参数, 返回修改后的状态

reducers: {
  test(state, action) {  
    return {
      ...state,
      value: action.payload
    }
  }
}

Effect

类型: (context, action) => Promise<void>

context

{
  namespace,    // 当前 Model 的 namespace
  state,        // 当前 Model 的 state
  rootState,    // 所有 Model 的 state
  dispatch,     // action type 自动拼接上当前 Model 的 namespace 
  rootDspatch,  // 原始 dispatch
  delay,        // 延时器
}

Effect 用于处理异步逻辑,必须返回一个 Promise。可以包含任意异步操作,比如异步请求。在 Effect 中想要修改状态,只能通过提交 Reducer 完成。

effects: {
  async test(context, action) {
    // 可以触发 reducer 修改状态
    context.dispatch({
      type: 'reducer'
    });  
    
    // 也可以触发其他的 effect
    await context.dispatch({ 
      type: 'effect'
    }); 
  }
}

Middleware

类型: (context, action, next) => Promise<void>

Middleware 用于处理通用异步逻辑,必须返回一个 Promise,接收 context action next 参数。全局中间件会作用于所有 EffectModel 内部中间件只会作用于指定的 Effect。多个中间件执行顺序: 从左到右,从全局到局部,数据流向遵循洋葱模型。

  • 完成一个最简单的中间件
async function middleware(context, action, next) { 
  console.log('start'); // 前置逻辑
  await next();         // 必须调用 next 执行后续的 middleware 或者 effect
  console.log('end')    // 后置逻辑
}
  • 全局使用
import { addMiddlewares } from 'redux-effect-models';

addMiddlewares([middleware]);
  • Model 内使用,Middleware key 和被作用的 Effect key 必须保持一致
middlewares: {
  test: [middleware] // key = test
},
effects: {
  async test() {     // key = test
    ...
  }
}

API

reduxEffectModels(models, middlewares?)

参数

reduxEffectModels 接收两个参数

  • models: Model 组成的数组(必传)
  • middlewares: 全局 Middleware 组成的数组(可选)
import { reduxEffectModels } from 'redx-effect-models';

const { reducer, state, effect } = reduxEffectModels([model1, model2, model3, ...], [middleware1, middleware2, middleware3, ...]);

返回值

reduxEffectModels 返回含有 reducer state effect 这三个属性的对象, 这三个属性都是 Redux createStore() 的参数

import { createStore, applyMiddleware } from 'redux';

const store = createStore(reducer, state, applyMiddleware(effect));

registerModel(model)

参数

model 需要注册的 Model

import { ActionType, registerModel } from 'redux-effect-models';

registerModel(model);

// 注册后需要调用 dispatch 同步数据
store.dispatch({
  type: ActionType.REGISTER
});

unregisterModel(namespace)

参数

namespace 需要被取消注册 Model 的 namespace

import { ActionType, unregisterModel } from 'redux-effect-models';

unregisterModel(namespace);

// 取消注册后需要调用 dispatch 同步数据
store.dispatch({
  type: ActionType.UNREGISTER
});

addMiddleware(middleware)

参数

middleware 需要添加的 Middleware

import { addMiddleware } from 'redux-effect-models';

addMiddleware(middleware);

removeMiddleware(middleware)

参数

middleware 需要删除的 Middleware

import { removeMiddleware } from 'redux-effect-models';

removeMiddleware(middleware);
1.5.0

4 years ago

1.3.9

4 years ago

1.3.8

4 years ago

1.3.7

4 years ago

1.3.6

4 years ago

1.3.5

4 years ago

1.3.3

4 years ago

1.3.2

4 years ago

1.3.1

4 years ago

1.3.0

4 years ago

1.2.75

4 years ago

1.2.73

4 years ago

1.2.78

4 years ago

1.2.76

4 years ago

1.2.77

4 years ago

1.2.72

4 years ago

1.2.7

4 years ago

1.2.71

4 years ago

1.2.66

4 years ago

1.2.63

4 years ago

1.2.65

4 years ago

1.2.62

4 years ago

1.2.6

4 years ago

1.2.5

4 years ago

1.2.61

4 years ago

1.2.32

4 years ago

1.2.31

4 years ago

1.2.3

4 years ago

1.2.28

4 years ago

1.2.29

4 years ago

1.2.26

4 years ago

1.2.256

4 years ago

1.2.255

4 years ago

1.2.251

4 years ago

1.2.25

4 years ago

1.2.236

4 years ago

1.2.233

4 years ago

1.2.235

4 years ago

1.2.232

4 years ago

1.2.231

4 years ago

1.2.23

4 years ago

1.2.22

4 years ago

1.2.21

4 years ago

1.2.2

4 years ago

1.2.20

4 years ago

1.2.1

4 years ago

1.2.0

4 years ago

1.1.62

4 years ago

1.1.61

4 years ago

1.1.60

4 years ago

1.1.6

4 years ago

1.1.50

4 years ago

1.1.393

4 years ago

1.1.392

4 years ago

1.1.391

4 years ago

1.1.38

4 years ago

1.1.39

4 years ago

1.1.37

4 years ago

1.1.36

4 years ago

1.1.35

4 years ago

1.1.33

4 years ago

1.1.32

4 years ago

1.1.30

4 years ago

1.1.31

4 years ago

1.1.29

4 years ago

1.1.28

4 years ago

1.1.27

4 years ago

1.1.26

4 years ago

1.1.25

4 years ago

1.1.23

4 years ago

1.1.22

4 years ago

1.1.19

4 years ago

1.1.18

4 years ago

1.1.21

4 years ago

1.1.20

4 years ago

1.1.17

4 years ago

1.1.16

4 years ago

1.1.15

4 years ago

1.1.13

4 years ago

1.1.12

4 years ago

1.1.11

4 years ago

1.1.10

4 years ago

1.1.1

4 years ago

1.1.0

4 years ago

1.0.9

4 years ago

1.0.8

4 years ago

1.0.7

4 years ago

1.0.6

4 years ago

1.0.5

4 years ago

1.0.4

4 years ago

1.0.2

4 years ago

1.0.3

4 years ago

1.0.1

4 years ago

1.0.0

4 years ago