1. 程式人生 > >詳解redux非同步操作示例

詳解redux非同步操作示例

#一、redux基礎

redux

  • 通過 dispatch(action) -> 中介軟體 -> reducer處理資料 -> 改變store -> 使用subscribe()監聽store改變更新檢視 的方式管理狀態
  • 將所有狀態儲存在一個store物件裡面
  • reducer為純函式,而非同步操作由於結果的不確定性所以含有副作用,所以需要特殊處理
    react-redux
    容器元件,負責管理資料和業務邏輯,不負責UI呈現
    UI元件,提供UI呈現,無狀態即不使用this.state,狀態全部由this.props提供
    由connect生成容器元件,每次store改變會呼叫connect,connect接收兩個引數: mapStateToProps, mapDispatchToProps
    mapStateToProps,將狀態對映到UI元件的props
    mapDispatchToProps,將dispatch方法對映到UI元件的props
    Provider元件,使用content API將store從頂層開始傳到每一層component供connect使用
    #二、redux處理非同步的中介軟體
    redux-thunk

    redux-thunk中介軟體允許action是一個方法
    中介軟體收到action後會執行action方法並將結果提供給reducer
    action混亂導致不易維護
    redux-saga
    saga會監聽action並基於這個action執行Effects操作
    Effects提供靈活的API,包括阻塞、非阻塞呼叫,取消、等待、race等操作
    方便隔離並執行非同步操作,並易於測試
    #三、redux-request-async-middleware
    先從redux文件中的非同步action說起,每個介面呼叫需要dispatch三個同步action,分別是:
    一種通知 reducer 請求開始的 action。對於這種 action,reducer 可能會切換一下 state 中的 isFetching 標記。以此來告訴 UI 來顯示載入介面。
    一種通知 reducer 請求成功的 action。對於這種 action,reducer 可能會把接收到的新資料合併到 state 中,並重置 isFetching。UI 則會隱藏載入介面,並顯示接收到的資料。
    一種通知 reducer 請求失敗的 action。對於這種 action,reducer 可能會重置 isFetching。另外,有些 reducer 會儲存這些失敗資訊,並在 UI 裡顯示出來。
    也就是一個介面發起是這樣的
dispatch(fetchPostsRequest(subject));
fetch(url).then(res => {
  dispatch(fetchPostsSuccess(subject, res));
}).catch(e => {
  dispatch(fetchPostsFailure(subject, e));
})

只是將這個操作封裝進中介軟體裡,特殊的地方在於:

  • 所有的非同步請求共用這三個action
  • 用subject來區分是哪一個請求
  • 將所有的結果都放到store.requests裡
    中介軟體原始碼
export const reduxRequest = store => next => action => {
  let result = next(action);
  let { type, subject, model } = action;
  let _next = action.next;
  if(type === FETCH_POSTS_REQUEST) {
    model().then(response => {
      _next && _next(response);
      store.dispatch(fetchPostsSuccess(subject, response));
    }).catch(error => {
      console.error(error);
      store.dispatch(fetchPostsFailure(subject, error));
    });
  }
  return result
};//歡迎加入全棧開發交流圈一起學習交流:864305860
  • 和redux-thunk一樣,將方法放進action裡
  • 中介軟體攔截FETCH_POSTS_REQUEST action,並進行非同步處理
    reducer原始碼
export const requests = (state = {}, action) => {
  switch (action.type) {
    case FETCH_POSTS_REQUEST:
      return assign({},
        state,
        {
          [action.subject]: {
            isFetching: true,
            state: 'loading',
            subject: action.subject,
            response: null,
            error: null,
          }
        }
      );
    case FETCH_POSTS_FAILURE:
      return assign({},
        state,
        {
          [action.subject]: {
            isFetching: false,
            state: 'error',
            subject: action.subject,
            response: state[action.subject].response,
            error: action.error,
          }//歡迎加入全棧開發交流圈一起學習交流:864305860
        }//面向1-3年前端人員
      );//幫助突破技術瓶頸,提升思維能力
    case FETCH_POSTS_SUCCESS:
      return assign({},
        state,
        {
          [action.subject]: {
            isFetching: false,
            state: 'success',
            subject: action.subject,
            response: action.response,
          }
        }
      );
    case FETCH_POSTS_CLEAR:
      return assign({},
        state,
        {
          [action.subject]: {
            isFetching: false,
            state: 'cleared',
            subject: null,
            response: null,
            error: null,
          }//歡迎加入全棧開發交流圈一起學習交流:864305860
        }//面向1-3年前端人員
      );//幫助突破技術瓶頸,提升思維能力
    default:
      return state;
  }
}
  • 將結果放入該subject對應下的response,如果錯誤的話將錯誤資訊放入error當中
  • isFetching表示當前的請求狀態
  • 另外還加入了當前的狀態state和subject資訊
    將請求進行封裝
const request = (subject, model, next) => {
  _dispatch(fetchPostsRequest(subject, model, next));
  return true;
};
  • 寫一個方法來發起FETCH_POSTS_REQUEST action
  • 也就是說寫請求的時候不用再管action這東西了,直接呼叫request方法
    將結果進行封裝
const getResponse = state =>
  state
  && state.response !== null
  && state.response;
 
const getLoading = (states = []) =>
  states.reduce((pre, cur) =>
    pre || (cur && cur.isFetching)
    , false)//歡迎加入全棧開發交流圈一起學習交流:864305860
  || false;//面向1-3年前端人員
//幫助突破技術瓶頸,提升思維能力
  1. 可以獲取結果和多個請求下loading的狀態
  2. 有更多的操作或者格式還可以繼續封裝,比如列表

四、總結

  1. 使用了redux來進行狀態管理,而並不需要編寫redux那一套複雜邏輯,最大程度的減少非同步操作的複雜度
  2. 適用於前端通過介面來處理和儲存資料的專案
  3. 介面由redux處理,而檢視元件由內部state來處理,而外部只暴露簡單的介面來進行操作,分離業務層和檢視層
  4. 對比react 16.3 new content API,redux的優勢在於熱插播的中介軟體和純函式reducer寫法

本次給大家推薦一個免費的學習群,裡面概括移動應用網站開發,css,html,webpack,vue node angular以及面試資源等。
對web開發技術感興趣的同學,歡迎加入Q群:864305860,不管你是小白還是大牛我都歡迎,還有大牛整理的一套高效率學習路線和教程與您免費分享,同時每天更新視訊資料。
最後,祝大家早日學有所成,拿到滿意offer,快速升職加薪,走上人生巔峰。