React從入門到放棄(4):Redux中間件

redux 提供了相似後端 Express 的中間件概念。
最適合擴展的是redux中的 store.dispatch 方法,中間件實際就是經過 override redux的store.dispatch() 完成
將 action -> reducer 過程變爲 action -> middlewares -> reducer 如:git

let next = store.dispatch;
store.dispatch = function dispatchAndLog(action) {
  console.log('dispatching', action);
  next(action);
  console.log('next state', store.getState());
}

添加中間件

redux提供了 applyMiddleware 方法便於添加中間件github

applyMiddleware的源碼:redux

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

異步操做

  1. 同步操做只要發出一種 Action 便可,異步操做一般須要發出多種 Action(開始、成功、失敗)
  2. 異步操做有2種Action寫法(3種type 或者 添加erro 和 response字段)
  3. 異步操做的state結構調整

Action寫法:app

// 寫法一:名稱相同,參數不一樣
{ 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等信息。async

示例:ide

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

相關文章
相關標籤/搜索