redux异步action_一文全解Redux中间件 & applymiddleware 柯里化 redux thunk

Redux核心概念

Redux的核心概念其实很简单:将需要修改的state都存入到store里,发起一个action用来描述发生了什么,用reducers描述action如何改变state tree 。创建store的时候需要传入reducer,真正能改变store中数据的是store.dispatch API。
Reducer:纯函数,只承担计算 State 的功能,不合适承担其他功能,也承担不了,因为理论上,纯函数不能进行读写操作。(功能有限 需要中间件)
Action:存放数据的对象,即消息的载体,只能被别人操作,自己不能进行任何操作。

Redux中间件

dispatch一个action之后,到达reducer之前,进行一些额外的操作,就需要用到middleware。 你可以利用 Redux middleware 来进行日志记录、创建崩溃报告、调用异步接口或者路由等等。
换言之,中间件都是对store.dispatch()的增强。
不难发现:

  1. 不使用middleware时,在dispatch(action)时会执行rootReducer,并根据action的type更新返回相应的state。
  2. 而在使用middleware时,简言之,middleware会将我们当前的action做相应的处理,随后再交付rootReducer执行。
    https://cn.redux.js.org 中文官方文档

955bd6e296b694763d320531ce76de8d.png


注意,不太需要研究如何写中间件,因为:常用的中间件都有现成的,只要引用别人写好的模块即可。
故 只要按照中间件官方提供的规定格式 实现程序,并应用到中间件方法,那么,在执行一个action的时候,就会成功调用中间件。

中间件 的软件工程定义是什么

中间件不是产出最终结果,而是 处理一些 程序流程中间 的操作。
作用:中间件常做一些 业务逻辑之间 的数据转换,让开发者不需要关注底层逻辑,而专心于当前的开发。
Middleware makes it easier for software developers to implement communication and input/output, so they can focus on the specific purpose of their application. -- Wiki
比如 ajax==>json(乱的数据)==>service转换(中间件)==>UI(整齐的数据)

示例:使用redux中间件

applymiddleware将一堆函数封装成一个函数,这些函数的执行顺序由next传递。

import { createStore, applyMiddleware } from 'redux';

// 中间件为 高阶函数:1.函数做参数 2.return出的也只是函数
const logger1 = store => next => action => { //柯里化:next函数 在store的源码中被一番处理后返回(高阶函数),新next再接收参数action
    console.log('current dipatch' + JSON.stringify(action));
    next(action);
};
const logger2 = store => next => action=> {
    next(action);
};
const logger3 = store => next => action=> {
    next(action);
};

const enhancer = applyMiddleware(logger1, logger2, logger3); //enhancer为一个函数,否则报错
const reducer = (state, action) => state;
const store = createStore(reducer, {}, enhancer); //{}为初始化的store数据
store.dispatch({type:1});
store.dispatch({type:2});
store.dispatch({type:3});
//createStore第3个参数enhancer若存在,将先执行enhancer内的中间件逻辑后再dispatch,而后才执行reducer的逻辑。
//可见中间件增强enhance了reducer&createStore

详解JS函数柯里化 - 简书柯里化:多参函数->单参函数
就是把一个由多个参数的函数,写成 多个函数嵌套,每个函数只有1个参数,每个函数返回下一个函数。

redux不用中间件 的代码书写顺序
action ==> dispatch ==> reducer ==> nextState

redux用中间件 的代码书写顺序 (middleware是在dispatch和reducer之间起作用)
action ==> middleware ==> dispatch ==> reducer ==> nextState

如何自己写一个中间件

在官方的示例中,有一个logger实现的示例

const logger = store => next => action =>{
    console.log('prev state',store.getState()) //获取状态数据
    console.log('dispatch',action);

    let result = next(action);

    console.log('next state',store.getState());

    return result;
}

从这个示例可以看出,实现一个中间件需要做一下几件事情:

  1. 三层函数包装:第一层传入store,第二层传入下一个中间件next,第三层传入此次执行的action;
  2. 在最内层的函数实现中,需要调用next中间件,并返回结果。
    参考 https://www.jianshu.com/p/dbe65d95c77b

applyMiddleware与redux中间件的原理

封装改造store.dispatch,将其指向中间件,以实现 在dispatch和reducer之间 处理action数据的逻辑。
大体原理如下

// 储存原来的dispatch
const dispatch = store.dispatch;

// 改变dispatch指向
store.dispatch = dispatchPre; //指向中间件

// 重命名
const next = dispatch;

参考 源码分析 https://segmentfault.com/a/1190000018347235

redux-thunk中间件+applymiddleware 实现 能异步的reducer

Redux store 默认仅支持同步数据流。 使用 thunk中间件 可以帮助在 Redux 应用中实现 异步的reducer。比如,action中 有setTimeout、ajax/fetch调用远程API 这些场景,就可用thunk中间件。
可以将 thunk中间件 看做 store 的 dispatch() 方法的封装器。我们可以使用 thunk的"action creator结构函数"来派遣 函数或Promise,而不是返回 action 对象,,具体如下。
背景: 没有 thunk 的话,默认地是同步派遣。虽然,同步机制 依然可以从React组件发出API调用(例如使用componentDidMount()生命周期方法发出这些请求),但在Redux应用中,同步派遣 难以实现以下两点:1.可重用性(思考下合成) 2.可预测性,只有 action creator 可以是状态更新的单一数据源。

直接将thunk中间件引入,放在applyMiddleware方法之中,传入createStore方法,就完成了store.dispatch()的功能增强。即可以在reducer中进行一些异步的操作。

import { applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
import reeducers from '....';
const store = createStore(
  reducers, 
  applyMiddleware(thunk, logger) //thunk本身是一个中间件,logger也是一个中间件,还可以放更多
); //thunk的实例被传递给Redux的applyMiddleware() enhancer函数

其实applyMiddleware就是Redux的一个原生方法,将所有中间件组成一个数组,依次执行。中间件多了可以当做参数依次传进applyMiddleware。

Redux-thunk可以让reducer直接使用 异步操作,通过把 异步的action creator 放入reducer中。如下就是个action creator,它必须返回一个函数(而非对象),可以是异步函数

export function addCount() {
  return {type: ADD_COUNT}
}
export function addCountAsync() { 
  return dispatch => {
    setTimeout( () => {
      dispatch(addCount())
    },2000)
  }
}

addCountAsync函数就返回了一个函数,将dispatch作为函数的第一个参数传递进去,在函数内进行异步操作就可以了。

该部分参考如下
redux-thunk的源码分析和更多操作 见
Redux中间件之redux-thunk使用详解 - 简书 源码分析
Redux-thunk中间件 - 简书 使用方法 如何写异步ajax的fetch+promise接收数据

全文参考

阮一峰 -- Redux 入门教程(二):中间件与异步操作 (涉及redux-thunk redux-promise) https://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_two_async_operations.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值