[三元學Redux]Redux中間件(thunk+saga應用)

1、什麼是Redux的中間件?

所謂中間件,必定是處於兩個事物的中間,那麼什麼是Redux中間件呢?ios

回顧一下Redux的工做流程:chrome

Redux的中間件,處於Action和Reducer之間,將中間某個過程攔截一下,進行一些處理再繼續正常執行,這就是中間件的功能。

那爲何要用到Redux中間件呢?npm

對於異步請求的代碼,咱們最好將它們放到Redux中間件裏面。redux

當項目複雜到必定規模的時候,咱們但願讓各個模塊儘量的實行單一職責,好比React做爲一個視圖層的框架就只負責渲染,數據的事情通通交給Redux來處理,此時,相對於把異步請求的Ajax代碼放到寫到組件的componentDidMount生命週期鉤子函數,其實交給Redux是一種更好的選擇。另外,交給Redux,一方面可以作到不一樣組件的接口複用,另外一方面方便於測試,單純去測試一些異步代碼比測試一個React組件的生命週期函數會更加容易。 然而Redux裏面dispatch的過程當中只容許傳遞對象,而不容許傳遞函數。因而,redux-thunk便應運而生。axios

2、Redux-thunk實現異步更新state

npm install redux-thunk --save
複製代碼

首先在項目中啓用redux-thunk網絡

//src/store/index.js
import {createStore, applyMiddleware, compose} from 'redux';
import reducer from './reducer';
import thunk from 'redux-thunk'
import TodoSagas from './sagas'

//須要同時激活redux-devtools的chrome插件,下面是激活代碼
//兼容代碼在redux-devtools的文檔下拿過來照着用便可
const composeEnhancers =
  typeof window === 'object' &&
  window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?   
    window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;

const enhancer = composeEnhancers(applyMiddleware(thunk))
//建立store
const store = createStore(
  reducer,
  enhancer
)

export default store;
複製代碼
//src/store/actionCreators.js
//如下爲getTodoList部分
export const getTodoList = () => {
  return (dispatch) => {
    axios.get('xxx').then((res) => {
      const data = res.data.list
      //建立action
      const action = initListAction(data)
      //至關於store.dispatch
      //其實redux-thunk給當前返回函數中添加的第一個默認參數就是store的dispatch方法
      dispatch(action)
    })
  }
}
複製代碼
//App.js
  componentDidMount() {
    // axios.get('xxx').then((res) => {
    // const data = res.data.data
    // const action = initListAction(data)
    // store.dispatch(action)
    // })
    //將以上代碼放進Redux,效果相同
    const action = getTodoList()
    store.dispatch(action)
  }
複製代碼

所以,redux-thunk實際上是攔截了store的dispatch方法,Redux中store.dispatch本來是不能傳一個函數進去的,可是redux-thunk讓dispatch擁有的接受函數參數的能力。具體來講,若是dispatch方法中傳遞的是一個對象,那麼直接按照正常的Redux工做流來運行,但若是是一個函數,那麼直接執行它,並把store.dispatch這個方法看成第一個參數傳進這個函數。app

3、Redux-saga實現異步更新state

redux-saga也是Redux中處理異步函數的中間件。框架

npm install redux-saga --save
複製代碼

首先在項目中啓動redux-saga:異步

//src/store/index.js
import {createStore, applyMiddleware, compose} from 'redux';
import reducer from './reducer';
import createSagaMiddleware from 'redux-saga'
import TodoSagas from './sagas'
//建立中間件
const sagaMiddleware = createSagaMiddleware()
//須要同時激活redux-devtools的chrome插件,下面是激活代碼
const composeEnhancers =
  typeof window === 'object' &&
  window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?   
    window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;

const enhancer = composeEnhancers(applyMiddleware(sagaMiddleware))
//建立store
const store = createStore(
  reducer,
  enhancer
)
//啓動中間件
sagaMiddleware.run(TodoSagas)

export default store;
複製代碼
//sagas.js
import { takeEvery, put } from 'redux-saga/effects'
import { GET_INIT_LIST } from './actionTypes';
import { initListAction } from './actionCreators';
import axios from 'axios'
function* getInitList() {
  try {
    const res = yield axios.get('xxx')
    //拿到Ajax數據後,經過initListAction建立action對象
    //注意: 這是另外一個action:INIT_LIST_ACTION,直接改變state中的list的值
    const action = initListAction(res.data.list)
    //put至關於dispatch這個新的action
    yield put(action)
  }catch(e) {
    console.log('網絡請求失敗')
  }
}
//導出的mySaga須要寫成一個Generator函數,異步處理函數getInitList也應是Generator函數
function* mySaga() {
  //攔截GET_INIT_LIST這個action
  yield takeEvery(GET_INIT_LIST, getInitList);
}

export default mySaga
複製代碼
//App.js
  componentDidMount() {
    const action = getInitList()
    store.dispatch(action)
  }
複製代碼

因此你可以看到,在redux-saga當中的處理思路是: 先拋出一個相似於信號燈的action,redux-saga看到了這個信號燈,攔截下來,而後執行響應的異步函數,在這個異步函數拿到數據後,執行真正要更新state的action。在這個過程當中,做爲信號燈的action在reducer中並無具體關於state的邏輯編寫,而僅僅是給redux-saga發一個信號而已。函數

關於redux中間件一點小小的總結,但願對你們有所幫助。

相關文章
相關標籤/搜索