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()的增强。
不难发现:
- 不使用middleware时,在dispatch(action)时会执行rootReducer,并根据action的type更新返回相应的state。
- 而在使用middleware时,简言之,middleware会将我们当前的action做相应的处理,随后再交付rootReducer执行。
https://cn.redux.js.org 中文官方文档
注意,不太需要研究如何写中间件,因为:常用的中间件都有现成的,只要引用别人写好的模块即可。
故 只要按照中间件官方提供的规定格式 实现程序,并应用到中间件方法,那么,在执行一个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;
}
从这个示例可以看出,实现一个中间件需要做一下几件事情:
- 三层函数包装:第一层传入store,第二层传入下一个中间件next,第三层传入此次执行的action;
- 在最内层的函数实现中,需要调用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