优雅的redux异步中间件 redux-effect

不吹不黑,redux蛮好用。只是有时略显繁琐,叫我定义每一个action、action type、使用时还要在组件上绑定一遍,臣妾做不到呀!下面分享一种个人比较倾向的极简写法,仍有待完善,望讨论。

github: github.com/liumin1128/…

基于redux、async/await、无侵入、兼容性良好的异步状态管理器。

install

npm i -S redux-effect

// or
yarn add redux-effect
复制代码

use

import { createStore, applyMiddleware, combineReducers } from 'redux';
import { reduxReduers, reduxEffects } from 'redux-effect';

const models = [ test1, test2, ...];

const reducers = combineReducers(reduxReduers(models));
const middlewares = [ reduxEffects(models) ];

const store = createStore(
    reducers,
    initialState,
    middlewares
  );
复制代码

从代码可以看出,从reduxReduers, reduxEffects中得到的就是标准的reducer和middleware,完美兼容其他redux插件,也可以轻松整合进老项目中。

完整例子:example

model

在redux-effect中,没有action的概念,也不需要定义action type。

所有关于某个state的一切声明在一个model中,本质就是一个对象。

export default {
  namespace: 'test',
  state: { text: 'hi!' },
  reducers: {
    save: (state, { payload }) => ({ ...state, ...payload }),
    clear: () => ({})
  },
  effects: {
    fetch: async ({ getState,dispatch }, { payload }) => {
      await sleep(3000);
      await dispatch({ type: 'test/clear' });
      await sleep(3000);
      await dispatch({ type: 'test/save', payload: { text: 'hello world' } });
    }
  }
};

复制代码

namespace:

model的命名空间,对应state的名字,必填,只接受一个字符串。

state:

state的初始值,非必填,默认为空对象

reducers:

必填,相当于同步执行的action方法,接受两个参数state和action,合并后返回新的state状态值。

effects:

非必填,相当于异步执行的action方法,接受两个参数store和action,store里包括redux自带的getState和dispatch方法,action为用户dispatch时带的参数。

dispatch

这里的dispatch就是redux中的dispatch,但有几个约定。

  1. 不传定义好的action,而是直接传一个普通对象。
  2. type的组织形式:namespace + '/' + reducer或effect方法名
  3. 参数的传递:需要合并的参数用payload包裹

定义每一个action,并将其绑定到视图层过于繁琐,去action化则让事件的触发变的灵活。

普通事件

发送事件时,不区分同步还是异步,只管dispatch,一切都已在model中定义好。

// 同步
dispatch({ type: 'test/save', payload: { text: "hello world" } })
// 异步
dispatch({ type: 'test/fetch' })
复制代码

等待

等待一个事件完成再执行逻辑,dispatch方法是可以被await的,十分轻松。

async function test() {
  await dispatch({ type: 'test/fetch' })
  await console.log('hello world')
}
复制代码

回调

等待某个事件,再执行外部定义的某个回调函数,只需要在action字段里加上callback方法,在effect中调用即可。

相比较await,回调可以拿到某些返回值,也可以在effect流程的中间部分执行。


dispatch({ type: 'test/fetch', callback1, callback2 })

{
  effects: {
    fetch: async ({ getState,dispatch }, { payload, callback, callback2 }) => {
      const state = await getState()
      await sleep(3000);
      await callback1(state)
      await sleep(3000);
      await callback2(state)
    }
  }
}
复制代码

自定义reducer

reducer其实就是redux中的reducer,用法完全一样。比如定义一个push方法,将后续数据,压入到原有数据后面,可以这样写。

export default {
  namespace: 'test',
  state: { data: [] },
  reducers: {
    save: (state, { payload }) => ({ ...state, ...payload }),
    clear: () => ({}),
    push: (state, { payload = {} }) => {
      const { key = 'data', data } = payload;
      return { ...state, [key]: state[key].concat(data) };
    }
  },
};
复制代码

自定义effect

effect其实就是一个普通async函数,接受store和action两个参数,可以使用async/await,可以执行任意异步方法,可以随时拿到state的值,可以dispatch触发另一个effect或者reducer。

loading

也许你会想监听某个effect,拿到loading状态,以便在ui给用户一个反馈。一般情况下监听一个异步方法,只需要在effect的开头和结束,各自设定状态即可,与常规写法无异。

但这里也提供一种model级别的loading状态,新增一个名为loading的model,再使用reduxEffectsWithLoading包裹需要监听的model即可。

关于model-creator

以上所做的事情,是将redux核心规范为model,得到了统一且可以复用的数据模型,这为自动生成model创造了可能性,如果能通过工厂模式,自动化创建具有类似功能,且可以随意装配的model,一切将变得更加美好。

Coming Soon

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值