Redux-saga官方文檔知識點記錄基礎(chǔ)部分

整理和總結(jié)官方文檔的中文翻譯版上面對于Redux-sage的介紹
文檔地址:http://leonshi.com/redux-saga-in-chinese/index.html

概述

redux-saga 是一個用于管理Redux 應用異步操作的中間件(又稱異步 action)。 redux-saga 通過創(chuàng)建 Sagas 將所有的異步操作邏輯收集在一個地方集中處理,可以用來代替 redux-thunk中間件。
   Sagas 只會在應用啟動時調(diào)用。 Sagas 可以被看作是在后臺運行的進程。Sagas 監(jiān)聽發(fā)起的 action,然后決定基于這個 action 來做什么:是發(fā)起一個異步調(diào)用(比如一個 Ajax 請求),還是發(fā)起其 他的 action 到 Store,甚至是調(diào)用其他的 Sagas。
   在 redux-saga 的世界里,所有的任務都通用 yield Effects 來完成(譯注:Effect 可以看作是 redux-saga 的任務單元)。Effects 都是簡單的 Javascript 對象,包含了要被 Saga middleware 執(zhí)行的信息(打個比方,你可以看到 Redux action 其實是一個個包含執(zhí)行信息的對象)
   因為使用了 Generator,redux-saga讓你可以用同步的方式寫異步代碼。

基本概念

1 Saga 輔助函數(shù)

takeEvery :允許多個 fetchData實例同時啟動。在某個特定時刻,我們可以啟動一個新的 fetchData任務, 盡管之前還有一個或多個 fetchData尚未結(jié)束。
   takeLatest:只允許執(zhí)行一個 fetchData任務。并且這個任務是最后被啟動的那個。 如果之前已經(jīng)有一個任務在執(zhí)行,那之前的這個任務會自動被取消。
例子:

import { takeEvery } from 'redux-saga'
function* watchFetchData() {
    yield* takeEvery('FETCH_REQUESTED', fetchData)
}```
   監(jiān)聽 FETCH_REQUESTED action 之后執(zhí)行下面的異步action 任務

import { call, put } from 'redux-saga/effects'
export function* fetchData(action) {
try {
const data = yield call(Api.fetchUser, action.payload.url);
yield put({type: "FETCH_SUCCEEDED", data});
} catch (error) {
yield put({type: "FETCH_FAILED", error});
}
}

#####2 聲明式 Effects
   我們從 Generator 里 yield 純 JavaScript 對象以表達 Saga 邏輯。 我們稱呼那些對象為 *Effect*。Effect 是一個簡單的對象,這個對象包含了一些給 middleware 解釋執(zhí)行的信息。 你可以把 Effect 看作是發(fā)送給 middleware 的指令以執(zhí)行某些操作(調(diào)用某些異步函數(shù),發(fā)起一個 action 到 store)。
   一個 Saga 所做的實際上是組合那些所有的 Effect,共同實現(xiàn)所需的控制流。 最簡單的是只需把 yield 一個接一個地放置,就可對 yield 過的 Effect 進行排序。
   我們已經(jīng)看到,使用 Effect 諸如 call 和 put,與高階 API 如 takeEvery相結(jié)合,讓我們實現(xiàn)與redux-thunk 同樣的東西, 但又有額外的易于測試的好處。
######2.1 Effect 概念是如何讓 Sagas 很容易地被測試的
   假設(shè)我們有一個監(jiān)聽 PRODUCTS_REQUESTED action 的Saga。每次匹配到 action,它會啟動一個從服務器上獲取產(chǎn)品列表的任務。
   現(xiàn)在要對這段邏輯編寫測試, 在測試過程中,執(zhí)行真正的服務是一個既不可行也不實用的方法,所以我們必須 模擬函數(shù)。也就是說,我們需要將真實的函數(shù)替換為一個假的,這個假的函數(shù)并不會真的發(fā)送 AJAX 請求而只會檢查是否使用正確的參數(shù)調(diào)用方法。模擬使測試更加困難和不可靠。
   實際上對這段邏輯的測試我們需要的只是保證任務 yield 一個正確的函數(shù),并且這個函數(shù)有著正確的參數(shù)。  **我們可以僅僅 yield 一條描述函數(shù)調(diào)用的信息** 
   實際中當yield 一個方法時,可以使用call(fn, ...args)這個函數(shù),**call創(chuàng)建了一條描述結(jié)果的信息**,call 只是一個返回純文本對象的函數(shù),redux-saga middleware 確保執(zhí)行函數(shù)調(diào)用并在響應被 resolve 時恢復 generator。
代碼示例

import { takeEvery } from 'redux-saga'
import Api from './path/to/api'
function* watchFetchProduts() {
yield* takeEvery('PRODUCTS_REQUESTED',fetchProducts)
}
function* fetchProducts() {
const products = yield call(Api.fetch, '/products')
}

//測試代碼
import { call } from 'redux-saga/effects'
import Api from '...'
const iterator = fetchProducts()
assert.deepEqual(
iterator.next().value, call(Api.fetch, '/products')

#####3 發(fā)起 action 到 store
   我們想發(fā)起一些action通知   
   dispatch({type:'PRODUCTS_RECEIVED', products })
           為了編寫方便測試的代碼,使用Effect的概念,使用指令的方式來發(fā)起通話,**只需創(chuàng)建一個對象來指示 middleware 我們需要發(fā)起一些 action,然后讓 middleware 執(zhí)行真實的 dispatch。**這種方式我們就可以同樣的方式測試 Generator 的 dispatch:只需檢查 yield 后的 Effect,并確保它包含正確的指令。指令為put
代碼示例

import { call, put } from 'redux-saga/effects'
//...
function* fetchProducts() {
const products = yield call(Api.fetch, '/products')
// 創(chuàng)建并 yield 一個 dispatch Effect
yield put({ type: 'PRODUCTS_RECEIVED', products })
}
//測試代碼
import { call, put } from 'redux-saga/effects'
import Api from '...'
const iterator = fetchProducts()
// 期望一個 call 指令
assert.deepEqual(
iterator.next().value, call(Api.fetch, '/products'),
"fetchProducts should yield an Effect call(Api.fetch,'./products')"
)
// 創(chuàng)建一個假的響應對象
const products = {}
// 期望一個 dispatch 指令
assert.deepEqual(
iterator.next(products).value, put({ type:'PRODUCTS_RECEIVED', products }),

   "fetchProducts should yield an Effect put({ type: 'PRODUCTS_RECEIVED', products })"

)

#####4 錯誤處理
   我們可以使用熟悉的 try/catch語法在 Saga 中捕獲錯誤。
代碼示例

import Api from './path/to/api'
import { call, put } from 'redux-saga/effects'
//...
function* fetchProducts() {
try {
const products = yield call(Api.fetch, '/products')
yield put({ type: 'PRODUCTS_RECEIVED', products })
} catch(error) {
yield put({ type: 'PRODUCTS_REQUEST_FAILED', error })
}
}
//測試代碼
import { call, put } from 'redux-saga/effects'
import Api from '...'
const iterator = fetchProducts()
// 期望一個 call 指令
assert.deepEqual(
iterator.next().value, call(Api.fetch, '/products'), "fetchProducts should yield an Effect call(Api.fetch, './products')"
)
// 創(chuàng)建一個模擬的 error 對象
const error = {}
// 期望一個 dispatch 指令
assert.deepEqual(
iterator.throw(error).value, put({ type: 'PRODUCTS_REQUEST_FAILED', error }),
"fetchProducts should yield an Effect put({ type: 'PRODUCTS_REQUEST_FAILED', error })"
)
//官網(wǎng)還提供了一種捕捉 Promise 的拒絕操作,并將它們映射到一個錯誤字段對象,可以查閱。個人喜歡第一種錯誤處理方式

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • 最近項目用了dva,dva對于異步action的處理是用了redux-saga,故簡單學習了下redux-saga...
    笨人不能懶閱讀 2,987評論 0 5
  • redux-saga框架使用詳解及Demo教程 前面我們講解過redux框架和dva框架的基本使用,因為dva框架...
    光強_上海閱讀 22,203評論 8 46
  • Redux-saga 概述 在 redux 一文中我們有說過處理異步我們應該放在 reducer 之前,所以我們需...
    滿是裂縫的花卷閱讀 2,539評論 0 2
  • Redux-saga 概述 redux-saga是一個用于管理redux應用異步操作的中間件,redux-saga...
    woow_wu7閱讀 51,983評論 11 41
  • 1. redux-thunk處理副作用的缺點 1.1 redux的副作用處理 redux中的數(shù)據(jù)流大致是: UI—...
    Grace_ji閱讀 3,669評論 0 14

友情鏈接更多精彩內(nèi)容