跳到主要内容

向存储库派发操作

进一步扩展上一个例子,假设每次保存后,我们想要派发一些操作来通知存储库获取操作已经成功(我们暂时忽略失败的情况)。

我们可以将存储库的 dispatch 函数传递给生成器。然后生成器在接收到获取响应后调用它:

// ...

function* fetchProducts(dispatch) {
const products = yield call(Api.fetch, '/products')
dispatch({ type: 'PRODUCTS_RECEIVED', products })
}

然而,这种解决方案与直接从生成器内部调用函数的缺点是一样的(如前一节所讨论的)。如果我们想要测试 fetchProducts 在接收到 AJAX 响应后执行派发,我们将需要再次模拟 dispatch 函数。

相反,我们需要相同的声明式解决方案。创建一个普通的 JavaScript 对象来指示中间件我们需要派发一些操作,并让中间件执行真正的派发。这样我们可以以相同的方式测试生成器的派发:通过检查生成的效果并确保它包含正确的指令。

为此目的,该库提供了另一个函数 put,用于创建派发效果。

import { call, put } from 'redux-saga/effects'
// ...

function* fetchProducts() {
const products = yield call(Api.fetch, '/products')
// 创建并产生一个派发效果
yield put({ type: 'PRODUCTS_RECEIVED', products })
}

现在,我们可以像在前一节中那样轻松地测试生成器

import { call, put } from 'redux-saga/effects'
import Api from '...'

const iterator = fetchProducts()

// 期望一个调用指令
assert.deepEqual(
iterator.next().value,
call(Api.fetch, '/products'),
"fetchProducts 应该产生一个 Effect call(Api.fetch, './products')"
)

// 创建一个假的响应
const products = {}

// 期望一个派发指令
assert.deepEqual(
iterator.next(products).value,
put({ type: 'PRODUCTS_RECEIVED', products }),
"fetchProducts 应该产生一个 Effect put({ type: 'PRODUCTS_RECEIVED', products })"
)

注意我们如何通过生成器的 next 方法传递假响应。在中间件环境之外,我们对生成器有完全的控制,我们可以通过模拟结果并用它们恢复生成器来模拟真实环境。模拟数据比模拟函数和监视调用要容易得多。