初识react(四) react中异步解决方案之 redux-saga
回顧
- 初識react(一) 揭開jsx語法和虛擬DOM面紗
- 初識react(二) 實現一個簡版的html redux.js的demo
- 初識react(三)在 react中使用redux來實現簡版計數器
- 初識react(四) react中異步解決方案之 redux-saga
- 初識react(五) 數據流終極解決方案 dva(零配置)
今天demo是實現一個異步的計算器,探究redux-saga工作流程
簡介
- redux-saga 是一個 redux 的中間件,而中間件的作用是為 redux 提供額外的功能。
- 由于在 reducers 中的所有操作都是同步的并且是純粹的,即 reducer 都是純函數,純函數是指一個函數的返回結果只依賴于它的參數,并且在執行過程中不會對外部產生副作用,即給它傳什么,就吐出什么。
- 但是在實際的應用開發中,我們希望做一些異步的(如Ajax請求)且不純粹的操作(如改變外部的狀態),這些在函數式編程范式中被稱為“副作用”。
redux-saga 就是用來處理上述副作用(異步任務)的一個中間件。它是一個接收事件,并可能觸發新事件的過程管理者,為你的應用管理復雜的流程。
redux-saga工作原理
- 對generator不了解的,看下阮一峰 generator講解
- sages 采用 Generator 函數來 yield Effects(包含指令的文本對象)。
- Generator 函數的作用是可以暫停執行,再次執行的時候從上次暫停的地方繼續執行
- Effect 是一個簡單的對象,該對象包含了一些給 middleware 解釋執行的信息。
- 你可以通過使用 effects API 如 fork,call,take,put,cancel 等來創建 Effect。
redux-saga分類
- worker saga 做左右的工作,如調用API,進行異步請求,獲取異步封裝結果
- watcher saga 監聽被dispatch的actions,當接受到action或者知道其被觸發時,調用worker執行任務
- root saga 立即啟動saga的唯一入口
基本介紹已經講完了,當做完一個demo后,回頭再看redux-saga官網或者上面講解,可能會有更深的體會
使用redux-saga實現一個異步計數器
由于目錄結構跟上篇文章一樣,在這里就只把變動的部分單獨抽離出來講解
- 先回顧下初識react(三)在 react中使用redux來實現簡版計數器
1、修改actions/counter.js
- 增加一個異步記數的動作類型。
2、重點,在src目錄下增加saga.js文件
//takeEvery=>負責監聽 put=>派發動作 call=>告訴saga,執行delay,并傳入1000作為參數 import {takeEvery,put,call} from "redux-saga/effects"; import * as Types from "./store/action-types"; const delay = ms=>new Promise((resolve,reject)=>{setTimeout(()=>{resolve()},ms) }) //saga分為三類 1、rootsaga 2、監聽saga 3、worker干活的saga function* add() {yield call(delay,1000);//就是指揮saga中間件向倉庫派發動作yield put({type:Types.INCREMENT,count:10}); } function* watchAdd() {//監聽派發給倉庫的動作,如果動作類型匹配的話,會執行對應的監聽生成器yield takeEvery(Types.ADD_ASYNC,add) } export default function* rootSaga() {yield watchAdd()}還記得上面說的,rudux-saga分類,root saga ->watcher saga -> worker saga。在這段代碼中將會體現,代碼我們從上往下看。
2.1 saga工作流程(代碼從下往上看)
- 默認導出了rootSaga,即saga的入口文件
- watcher saga ->wactchAdd 負責監聽派發的動作,如果動作類型匹配,執行對應的 worker saga
- 上面的worker saga指代的是 add函數
2.2 redux-saga/effects 副作用
在實際的應用開發中,我們希望做一些異步的(如Ajax請求)且不純粹的操作(如改變外部的狀態),這些在函數式編程范式中被稱為“副作用”。
- takeEvery=>負責監聽,監聽派發給倉庫的動作,如果動作類型匹配的話,會執行對應的監聽生成器->add
- put=>派發動作,可以理解為dispatch
- call=>告訴saga,執行delay函數,并把參數傳過去。注意: delay函數必須返回promise
講到這里,流程就說完了,接下來在store中執行rootSaga
3、在store/index引入rootSaga
import {createStore,applyMiddleware} from 'redux';import createSagaMiddleware from "redux-saga"; //引入redux-sagaimport rootSaga from "../saga" //引入我們上面寫好的rootSagaimport reducer from "./reducers"let sagaMiddleware =createSagaMiddleware(); //執行得到saga中間件let store = createStore(reducer,applyMiddleware(sagaMiddleware)); //使用中間件sagaMiddleware.run(rootSaga); //開始執行rootSagaexport default store;對于redux中間件沒有講解,這部分內容涉及東西比較多,也不太好理解,寫這個react系列目的是盡可能簡單的讓所有人理解,想看所有的redux源碼解析,底部會留下所有總結的代碼倉庫。
4、在counter.js組件中派發這個異步動作
- 代碼跟上篇文章一模一樣,只是增加了按鈕實現異步操作
終結,看效果。可以看出,點擊后等待1s才加10。那我們就可以在call()中傳入執行的異步函數(如ajax)來獲取數據啦。我們這個例對應的delay函數
最后在梳理下整個過程
-
1、組件中調用了this.props.async(),返回的action對象=>{type:Types.ADD_ASYNC}會在connect方法中被派發
-
2、saga中takeEvery(Types.ADD_ASYNC,add),監聽到動作的類型后,觸發 worker saga =>add
-
3、worker saga中先 yield call(delay,1000); 執行delay方法,延時1s
-
4、yield put({type:Types.INCREMENT,count:10}); 最后派發的還是INCREMENT的類型
-
5、接著被reducer處理,更新state
-
6、頁面刷新
-
更多優質文章參考
-
redux所有源碼解析戳這里
總結
以上是生活随笔為你收集整理的初识react(四) react中异步解决方案之 redux-saga的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一个vue加egg.js的博客
- 下一篇: WePY:在质疑中前进 | 文末福利