傳送動作至儲存庫
讓我們更進一步看看前面的範例,假設我們想要在每次儲存後,傳送一些動作來通知儲存庫讀取成功(我們目前會略過失敗的情況)。
我們可以將儲存庫的 dispatch
函式傳遞至 Generator。然後 Generator 可以於收到讀取回應後呼叫它
// ...
function* fetchProducts(dispatch) {
const products = yield call(Api.fetch, '/products')
dispatch({ type: 'PRODUCTS_RECEIVED', products })
}
不過,這個解法有和直接在 Generator 裡面呼叫函式相同的問題(如前一節所述)。如果我們想要測試 fetchProducts
是否在收到 AJAX 回應後執行傳送,我們必須再模擬一次 dispatch
函式
相反,我們需要相同的宣告式解決方案。建立一個一般 JavaScript 物件,以指示我們需要派遣一些動作,並讓中間軟體執行實際調度。透過這種方式,我們可以用同樣的方法測試 Generator 的調度:檢查產生的效果,並確認它包含正確的指令。
圖書館為此目的提供了另一個函式 put
,用以建立調度效果。
import { call, put } from 'redux-saga/effects'
// ...
function* fetchProducts() {
const products = yield call(Api.fetch, '/products')
// create and yield a dispatch Effect
yield put({ type: 'PRODUCTS_RECEIVED', products })
}
現在,我們可以像前一節那樣輕易地測試 Generator
import { call, put } from 'redux-saga/effects'
import Api from '...'
const iterator = fetchProducts()
// expects a call instruction
assert.deepEqual(
iterator.next().value,
call(Api.fetch, '/products'),
"fetchProducts should yield an Effect call(Api.fetch, './products')"
)
// create a fake response
const products = {}
// expects a dispatch instruction
assert.deepEqual(
iterator.next(products).value,
put({ type: 'PRODUCTS_RECEIVED', products }),
"fetchProducts should yield an Effect put({ type: 'PRODUCTS_RECEIVED', products })"
)
請注意我們如何透過其 next
方法將偽造的回應傳遞給 Generator。在中間軟體環境之外,我們對 Generator 擁有完全的控制權,我們可以模擬真實的環境,透過模擬結果和使用它們繼續 Generator。模擬資料比模擬函式和監控呼叫容易得多。