React从入门到放弃之前奏(4):Redux中间件
redux 提供了类似后端 Express 的中间件概念。
最适合扩展的是redux中的 store.dispatch 方法,中间件实际就是通过 override redux的store.dispatch() 完成
将 action -> reducer 过程变为 action -> middlewares -> reducer 如:
let next = store.dispatch; store.dispatch = function dispatchAndLog(action) { console.log('dispatching', action); next(action); console.log('next state', store.getState()); }
添加中间件
redux提供了 applyMiddleware 方法便于添加中间件
applyMiddleware的源码:
export default function applyMiddleware(...middlewares) { middlewares = middlewares.slice() middlewares.reverse() // Transform dispatch function with each middleware. middlewares.forEach(middleware => // 由于每次middle会直接返回返回函数,然后在这里赋值给store.dispatch, // 下一个middle在一开始的时候,就可以通过store.dispatch拿到上一个dispatch函数 store.dispatch = middleware(store) ) }
通过middleware将 store.dispatch 进行扩展
middleware会返回一个函数:return store => dispatch => action => {}
异步操作
- 同步操作只要发出一种 Action 即可,异步操作通常需要发出多种 Action(开始、成功、失败)
- 异步操作有2种Action写法(3种type 或者 添加erro 和 response字段)
- 异步操作的state结构调整
Action写法:
// 写法一:名称相同,参数不同 { type: 'FETCH_POSTS' } { type: 'FETCH_POSTS', status: 'error', error: 'Oops' } { type: 'FETCH_POSTS', status: 'success', response: { ... } } // 写法二:名称不同 { type: 'FETCH_POSTS_REQUEST' } { type: 'FETCH_POSTS_FAILURE', error: 'Oops' } { type: 'FETCH_POSTS_SUCCESS', response: { ... } }
异步State结构:
let state = { // ... isFetching: true,// 正在获取数据 didInvalidate: true,// 是否过期 lastUpdated: 'xxxxxxx'// 上次更新时间 };
使用中间件
- 使用
createStore(reducer, enhancer)
或createStore(reducer, preloadedState, enhancer)
- applyMiddleware的参数为中间件,某些中间件有顺序要求如:logger
redux-logger
redux-logger 可清晰记录 preState action nextState time等信息。
示例:
import { createStore, applyMiddleware } from 'redux' import createLogger from 'redux-logger' import rootReducer from './reducers' let store = createStore(rootReducer, applyMiddleware(createLogger));
redux-thunk
redux-thunk 用来优化redux中的异步操作。
在store.dispatch 的方法参数只支持js对象(即Action),使用redux-thunk将支持参数为一个函数。
函数签名:(dispatch, getState) => {}
示例:
import { createStore, applyMiddleware } from 'redux' import thunkMiddleware from 'redux-thunk' import rootReducer from './reducers' let store = createStore(rootReducer, applyMiddleware(thunkMiddleware)); store.dispatch( dispatch => { dispatch({type:'CLICK_START',data:res}) fetch('xx') .then(res => dispatch({type:'CLICK_END',data:res})); } )
实际上,redux-thunk 的作用是让 Action Creator方便可以返回函数,这样让项目中的同步异步Action Creator调用可以保持一致
支持异步的还有redux-promise 和 redux-saga等