appstore-react v2.0—redux-actions和redux-saga的應用

開發文檔

  • https://redux-saga.js.org/
  • https://redux-saga-in-chinese.js.org/
  • https://redux-actions.js.org/

源碼

代碼已經上傳到github中,歡迎star或者forkreact

appstore-react-v2.0git

redux-saga

1、介紹

以前異步處理用的是redux-thunk + redux-actions + redux-promise,可是隨着ES6中Generator的出現,人們發現用Generator處理異步能夠更簡單。而redux-saga就是用Generator來處理異步。
redux-saga文檔並無說本身是處理異步的工具,而是說用來處理邊際效應(side effects),這裏的邊際效應你能夠理解爲程序對外部的操做,好比請求後端,好比操做文件。
redux-saga一樣是一個redux中間件,它的定位就是經過集中控制action,起到一個相似於MVC中控制器的效果。
同時它的語法使得複雜異步操做不會像promise那樣出現不少then的狀況,更容易進行各種測試。github

2、 安裝

npm install --save redux-saganpm

3、saga經常使用輔助函數

put、call、takeEvery、takeLatestredux

一、put和call

put至關於redux的dispatch的做用,而call至關於調用函數segmentfault

export function* delayChangeBtnText() {
  yield delay(1000);
  yield put(changeBtnText('123'));
  yield call(consoleMsg, '完成改變');
}
二、takeEvery

它提供了相似 redux-thunk 的行爲後端

import { takeEvery } from 'redux-saga'

function* watchFetchData() {
  yield* takeEvery('FETCH_REQUESTED', fetchData)
}
三、takeLatest

takeEvery 容許多個 fetchData 實例同時啓動。在某個特定時刻,儘管以前還有一個或多個 fetchData 還沒有結束,咱們仍是能夠啓動一個新的 fetchData 任務,
若是咱們只想獲得最新那個請求的響應(例如,始終顯示最新版本的數據)。咱們可使用 takeLatest輔助函數api

import { takeLatest } from 'redux-saga'

function* watchFetchData() {
  yield* takeLatest('FETCH_REQUESTED', fetchData)
}

4、使用

一、修改store/index.js
import { createStore, applyMiddleware } from 'redux';
// import thunk from 'redux-thunk';
import createSagaMiddleware from 'redux-saga';
import {watchAppSearch} from './sagas';
import rootReducer from './reducers';

/**
 * saga用法
 * 1.建立一個 Saga middleware
 * 2.使用 applyMiddleware 將 middleware 鏈接至 Store
 * 3.使用 sagaMiddleware.run(helloSaga) 運行 Saga
 */
const sagaMiddleware = createSagaMiddleware();


// 建立store的時候,第二個參數是中間件,redux-thunk提供了一個thunk中間件,用於處理異步的action
let store = createStore(
  rootReducer,
  applyMiddleware(sagaMiddleware)
);

// 運行並監控各個action
sagaMiddleware.run(watchAppSearch);

export default store
二、建立store/sagas.js
import { put, call, takeEvery,takeLatest } from 'redux-saga/effects';
import { actionCreators } from './action'
import $api from '../api/index.js';
/**
 * 處理編輯效應的函數
 */
export function* appSearch(action) {
  // 在saga中這裏經過action.payload獲取到前臺傳過來的keyword內容   
  const p = function(){
    return $api.lookUp({
      keyword:action.payload
    })
    .then(res => res.results)
    .then(res =>{
      return res
    })
  }
  const res = yield call(p); // 執行p函數,返回值賦值給res
  yield put(actionCreators.saveSearchList(res));// 經過put觸發dispatch ,將返回數據傳過去
}
/**
 * 監控Action的函數
 */
// takeLatest 和 takeEvery 不一樣,在任什麼時候刻 takeLatest 只容許一個 fetchData 任務在執行。
// 而且這個任務是最後被啓動的那個。 若是已經有一個任務在執行的時候啓動另外一個 fetchData ,那以前的這個任務會被自動取消。
export function* watchAppSearch() {
  yield takeEvery(actionCreators.appSearch, appSearch);
}
三、同時啓動多個Sagas 監聽action動做
// 同時啓動多個Sagas  監聽action動做
export default function* rootSaga() {
  yield all([
    takeLatest(actionCreators.appSearch, appSearch),
    takeLatest(actionCreators.getRecommendList, getRecommendList)
  ])
}

/**
 * app搜索獲取結果列表
 */
export function* appSearch(action) {
  // 在saga中這裏經過action.payload獲取到前臺傳過來的keyword內容   
  const p = function(){
    return $api.lookUp({
      keyword:action.payload
    })
    .then(res => res.results)
    .then(res =>{
      return res
    })
  }
  const res = yield call(p); // 執行p函數,返回值賦值給res
  yield put(actionCreators.saveSearchList(res));// 經過put觸發dispatch ,將返回數據傳過去
}


/**
 * 請求獲取推薦列表
 * @param {*} action 
 */
export function* getRecommendList(action) { 
  const p = function(){
    return $api.recommendData({})
    .then(res => res.feed)
    .then(res =>{
      return res
    })
  }
  const res = yield call(p); // 執行p函數,返回值賦值給res
  yield put(actionCreators.getRecommendListSucceeded(res.entry));
}

redux-actions

redux-actions用來簡化redux重複代碼,這部分簡化工做主要集中在構造action和處理reducers方面。promise

1、安裝

npm install --save redux-actionsapp

2、使用

-----action.js
import * as types from './action-types'
import { createActions } from 'redux-actions';

/**
 * 使用redux-actions以前
 */
// export const saveSearchList = (searchList) => {
//   console.log('searchList',searchList)
//   return {
//     type: types.SAVE_SERACH_LIST,
//     searchList
//   }
// }

// export const removeSearchList = () => {
//   return {
//     type: types.REMOVE_SERACH_LIST
//   }
// }

/**
 * 使用redux-actions以後
 */
// 使用createAction建立單個動做
// export const saveSearchList = createAction(types.SAVE_SERACH_LIST,searchList=>searchList);
// export const removeSearchList = createAction(types.REMOVE_SERACH_LIST);

// 使用createActions建立多個動做
export const actionCreators = createActions({
  [types.SAVE_SEARCH_LIST]:searchList=>searchList,
  [types.REMOVE_SEARCH_LIST]:()=>null
});
-----reducer.js
import * as types from './action-types'
import { handleActions } from 'redux-actions';

let defaultState = {
  searchList: []//搜索結果列表
}

/**
 * 使用redux-actions以前
 */
// 修改state
// export default(state = defaultState, action={})=>{
//   switch (action.type) {
//     case types.SAVE_SERACH_LIST:
//       return {
//         ...state,
//         searchList: action.searchList
//       }
//     case types.REMOVE_SERACH_LIST:
//       return{
//         ...state,
//         searchList:[]
//       }
//     default:
//       return state
//   }
// }

/**
 * 使用redux-actions以後
 */
// handleAction單個action處理
// const reducer = handleAction(types.SAVE_SERACH_LIST,(state, action)=>{
//   return {
//     ...state,
//     searchList: action.searchList
//   }
// },defaultState);


// 使用handleActions處理多個actions  ,這裏須要注意的是  經過action.payload獲取傳過來的數據
const reducerCreators = handleActions({
  [types.SAVE_SEARCH_LIST]:(state, action)=>{
    return {
      ...state,
      searchList: action.payload
    }
  },
  [types.REMOVE_SEARCH_LIST]:(state, action)=>{
    return{
      ...state,st
      searchList:[]
    }
  }
},defaultState);

export default reducerCreators;
---index.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { actionCreators } from '../../store/action'
/**
 * 使用redux-action以前
 */
// const mapDispatchToProps = (dispatch) => ({
  // 分發由action creators建立的actions
//   saveSearchList: searchList => dispatch(saveSearchList(searchList)),
//   removeSearchList: () => dispatch(removeSearchList())
// })


/**
 * 使用redux-action以後
 */
// createActions會返回一個對象,對象針對每一個action類型都有一個值爲action工廠的屬性,屬性名爲action類型的值去掉下劃線後的駝峯命名
const mapDispatchToProps = {
  saveSearchList:actionCreators.saveSearchList,
  removeSearchList:actionCreators.removeSearchList
}


// 經過connect生成容器組件
export default connect(mapStateToProps,mapDispatchToProps)(SearchResult);

源碼

代碼已經上傳到github中,歡迎star或者fork

appstore-react-v2.0

參考閱讀

  • https://juejin.im/post/5b41641ef265da0f8202126d
  • https://www.jianshu.com/p/d2615a7d725e
  • https://segmentfault.com/a/1190000017064759?utm_source=tag-newest
相關文章
相關標籤/搜索