2017年7月27日 星期四

Redux Thunks Tutorial


  • 通常asynchronous request有三個stage
    • Request開始
    • Request成功 
    • Request失敗

  • 假設有一個reducer其初始state如下
const initialState = {
  data: [],
  isFetching: false,
  error: ''
}

  • 這個Reducer長的如下,我們處理了上面提到的三個stage
function reducer (state = initialState, action) {
  switch (action.type) {
    case 'FETCHING_DATA' :
      return Object.assign({}, state, {
        isFetching: true
      })
    case 'FETCHING_DATA_ERROR' :
      return Object.assign({}, state, {
        isFetching: false,
        error: action.error,
      })
    case 'FETCHING_DATA_SUCCESS' : 
      return Object.assign({}, state, {
        isFetching: false,
        error: '',
        data: action.data
      })
  }
}


  • 他的Action Creator像下面這樣
function fetchingData () {
  return {
    type: 'FETCHING_DATA'
  }
}
function fetchingDataError (error) {
  return {
    type: 'FETCHING_DATA_ERROR',
    error: error.msg
  }
}
function fetchingDataSuccess (data) {
  return {
    type: 'FETCHING_DATA_SUCCESS',
    data,
  }
}

  • 接下來考慮一個常見的情況,我們可能在Component要mount的時候去發出asynchronous request,假設getData( )是一個asynchronous function會回傳一個Promise,他會以如下的方式跟Action Creator整合
componentDidMount () {
  fetchingData()
  getData()
    .then((data) => fetchingDataSuccess(data))
    .catch((error) => fetchingDataError(error))
}

  • 上面那樣看起來不錯,只是要把那些Action Creator都import到我們的Component有點麻煩,而且還得用bindActionCreators把他們跟dispatch bind起來,以及做PropTypes的檢查等。是不是把這些邏輯封裝到另一個Action Creator會更好呢?假設有一個Action Creator叫做fetchAndHandleData可以做到這些,那麼componentDidMount只要像這樣就好:
componentDidMount () {
  fetchAndHandleData()
}

  • 只是要做到這樣的話,就必須讓那個Action Creator得以存取dispatch,這就是redux-thunk出現的原因,他的想法是Action Creator不是回傳一個物件,而是回傳一個傳入dispatch的function,以上面的fetchAndHandleData為例大概會長的像這樣:
function fetchAndHandleData () {
  return function (dispatch) {
      dispatch(fetchingData())
      getData()
          .then((data) => dispatch(fetchingDataSuccess(data)))
          .catch((error) => dispatch(fetchingDataError(error)))
  }
}


  • 最後是實作的時候要import的東西,以及在createStore( )時多帶入一個參數
...
import thunk from 'redux-thunk'
import { createStore, applyMiddleware } from 'redux'
...
const store = createStore(users, applyMiddleware(thunk))
...





沒有留言:

張貼留言