redux系列之react-thunk源碼解讀

前言

咱們知道,redux提供了一套很好的狀態管理機制,經過在createStore方法建立出store對象,經過store.getState獲取狀態對象,經過reducer定義出action改變對應的state變化的規則,經過replaceReducer動態改變reducer規則,結合dispatch一個action來修改狀態對象state,甚至,redux還提供了applyMiddleware來給redux增長中間件,提供dispatch和getState2個方法給中間件使用;react

不過,redux只是一個和其餘庫無關的狀態管理庫,爲了可以方便的在react中使用,咱們必須結合react-redux來使用。react-redux經過Provider使用給react項目的全部子組件注入store,經過connect給組件注入state和dispatch。ajax

可是,有了react-redux還不夠!咱們還須要react-thunk!redux

爲何須要react-thunk?

ajax請求發出去的時候,常常涉及到這3個狀態:loading,success,error3個狀態,並且這3個狀態是在同一個地方產生的,那麼,若是僅有react-thunk,那麼,咱們須要在組件內部這樣寫代碼:api

this.props.dispatch(loadingAction);
ajax('/getData').then(res => {
    this.props.dispatch(successAction);
}).catch(err => {
    this.props.dispatch(errorAction);
})

若是上述代碼在組件內屢次被調用,就須要封裝成函數,getData,若是要誇頁面調,那就須要封裝到專門的api請求裏面去,代碼以下:app

//api.js
export function getData(dispatch) {
    this.props.dispatch(loadingAction);
    ajax('/getData').then(res => {
        this.props.dispatch(successAction);
    }).catch(err => {
        this.props.dispatch(errorAction);
    });
}

//index.js業務組件代碼
import {getData} from './api.js';
class MyComponent extends Component {
    handleClick() {
        getData(this.props.dispatch);
    }
}

而且,若是getData內部須要用到全局的state,那麼,咱們必需要從業務代碼裏面傳入getState函數,那麼代碼就會變成下面這樣:ide

//api.js
export function getData(dispatch, getState) {
    const state = getState();
    dispatch(loadingAction);
    ajax('/getData').then(res => {
        dispatch(successAction);
    }).catch(err => {
        dispatch(errorAction);
    });
}

//index.js業務組件代碼
import {getData} from './api.js';
class MyComponent extends Component {
    handleClick() {
        getData(this.props.dispatch, this.props.store.getState);
    }
}

彷佛這樣也行,可是,總感受不對,每次都要從業務組件裏面顯式的傳入2個參數dispatch和getState,這樣感受很煩。
因此呢,經過以上分析,咱們react-thunk就閃亮登場了!函數

react-thunk怎麼用?

//store.js
import thunk from 'redux-thunk';
const initialState = {};
const reducer = function(state={}, action){ return state };
const store = createStore(reducer, initialState, applyMiddleware(thunk));

//action.js
export function getData(dispatch, getState) {
    const state = getState();
    dispatch(loadingAction);
    ajax('/getData').then(res => {
        dispatch(successAction);
    }).catch(err => {
        dispatch(errorAction);
    });
}

//index.js業務組件代碼
import { getData } from './actions.js';

class MyComponent extends Component {
    handleClick() {
        getData();
    }
}

這樣,使用了react-thunk以後,咱們無需從getData中傳入dispatch和getState,而是中間件會默認幫咱們作這個事情,這樣,咱們就能夠在一個函數內部dispatch多個action,以及隨意的拿到全局的statethis

react-thunk怎麼實現的?

看源碼:spa

//一個建立thunk的中間件工廠函數
function createThunkMiddleware(extraArgument) {
  return ({ dispatch, getState }) => next => action => {
    if (typeof action === 'function') {
      return action(dispatch, getState, extraArgument);
    }

    return next(action);
  };
}
//建立出thunk中間件
const thunk = createThunkMiddleware();
//把工廠函數附屬到thunk對象上,方便高級用戶自定義傳入更多的參數到action中去
thunk.withExtraArgument = createThunkMiddleware;

export default thunk;

其實,就是一箇中間件的寫法,當發現action是一個函數的時候,就會傳入dispatch和getState這2個參數,而這2個參數是從中間件那裏傳過來的。code

全文完

相關文章
相關標籤/搜索