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 => {}

异步操作

  1. 同步操作只要发出一种 Action 即可,异步操作通常需要发出多种 Action(开始、成功、失败)
  2. 异步操作有2种Action写法(3种type 或者 添加erro 和 response字段)
  3. 异步操作的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'// 上次更新时间
};

使用中间件

  1. 使用createStore(reducer, enhancer)createStore(reducer, preloadedState, enhancer)
  2. 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将支持参数为一个函数。

或者说 redux-thunk 使得 action 从一个对象变成一个函数。

函数签名:(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-saga

redux-saga 相比thunk 功能显得全面,精细。
saga 是一个常驻进程,在复杂任务 及 长时事务场景非常适用。
这里通过2个action 来展示 saga

示例:

import createSagaMiddleware, { delay } from 'redux-saga'
import { all, put, takeEvery, takeLatest } from 'redux-saga/effects'

function* helloSaga() {
    yield delay(1000)
    console.log('hello world')
}

function* incrementAsync() {
    yield delay(1000)
    yield put({ type: 'click' })
}

function* rootSaga() {
    yield all([
        takeEvery('hello', helloSaga),
        takeLatest('async', incrementAsync)
    ])
}

let sagaMiddleware = createSagaMiddleware();

let store = createStore(rootReducer, applyMiddleware(sagaMiddleware))

sagaMiddleware.run(rootSaga);

store.dispatch({ type: 'hello' });
store.dispatch({ type: 'async' });

支持异步的还有redux-promise

posted @ 2018-05-23 11:28 Never、C 阅读(...) 评论(...) 编辑 收藏