Redux Saga异步/等待模式

mat*_*ich 33 redux redux-saga react-redux

我在整个代码库中使用async/await.因此,我的api调用由异步函数定义

async function apiFetchFoo {
  return await apiCall(...);
}
Run Code Online (Sandbox Code Playgroud)

我想从我的传奇代码中调用这个函数.好像我不能这样做:

// Doesn't work
function* fetchFoo(action) {
  const results = await apiFetchFoo();
  yield put({type: "FOOS_FETCHED_SUCCESSFULLY", foos: results});
}
Run Code Online (Sandbox Code Playgroud)

但是,这确实有效,并且与redux saga文档相匹配:

// Does work
function* fetchFoo(action) {
  const results = yield call(apiFetchFoo);
  yield put({type: "FOOS_FETCHED_SUCCESSFULLY", foos: results});
}
Run Code Online (Sandbox Code Playgroud)

这是使用Redux Saga和async/await的正确方法吗?在saga代码中使用这个生成器语法,在其他地方使用async/await模式是标准的吗?

Jos*_*sep 31

是的,这是使用Redux-Saga的标准方法.

你永远不应该await直接在saga-generator中调用函数,因为redux-saga用于编排副作用.因此,任何想要运行副作用的时候都应该通过redux-saga效果产生副作用(通常是:callfork).如果你直接做到而不通过redux-saga效果产生它,那么redux-saga将无法协调副作用.

如果你考虑一下,redux-saga发生器是完全可测试的,不需要嘲笑任何东西.此外,它有助于保持事物分离:如果你的apiFetchFoo回复承诺,传奇仍然会工作相同.

  • @modulitos确定!https://redux-saga.js.org/恐怕您不太了解redux-saga的含义。redux-saga生成器旨在协调副作用。如果您想做您要提到的事情,那么您就不应该在redux-saga生成器中进行此操作...您可以在普通生成器中进行-如果您愿意-或在其他promise中,则不能问题...然后在redux-saga生成器中产生一个`call`效果,该效果调用了promise / generator / every。 (3认同)
  • 是的,这很有意义!我认为我误解了redux-saga生成器的边界,并试图使其发挥更大的作用。相反,我应该等待被生成到传奇生成器中的实体的“无副作用”承诺。 (2认同)

Ari*_*rya 5

正如 Josep 所指出的,await不能在生成器中使用。相反,您需要使用异步函数。另外,请注意这是异步函数本身的限制。它不是由 redux-saga 强加的。

除此之外,我也想提一提,它是一种有意识的选择,通过了Redux-传奇创作者没有让开发者来表达传奇的async/await功能。

生成器比async/await它们更强大,它们允许使用 redux-saga 的高级功能,例如协调并行任务

此外,将 saga 表示为生成器有助于我们定义效果,即定义副作用的普通对象。效果使测试我们的传奇变得非常容易

因此,尽管您的工作代码很好,但最好不要将 saga 和 async 函数混为一谈。

只需定义您apiFetchFoo的返回一个承诺,该承诺通过对请求的响应来解决。当这种情况发生时,您的传奇将继续使用results.

 const apiFetchFoo = () =>
   fetch('foo')
     .then(res => res.json())
Run Code Online (Sandbox Code Playgroud)