web-dev-qa-db-ja.com

Redux Sagaの非同期/待機パターン

コードベース全体でasync/awaitを使用しています。このため、私のAPI呼び出しは非同期関数によって定義されています

async function apiFetchFoo {
  return await apiCall(...);
}

この関数を私のサガコードから呼び出したいです。私はこれを行うことができないようです:

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

ただし、これは機能し、redux sagaのドキュメントと一致します。

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

これはasync/awaitと一緒にRedux Sagaを使用する正しい方法ですか?サガコード内でこのジェネレーター構文を使用し、他の場所でasync/awaitパターンを使用するのが標準ですか?

30
mattnedrich

はい、それがRedux-Sagaを使用する標準的な方法です。

Redux-sagaはorchestratingの副作用のためであるため、await関数をsaga-generator内で直接呼び出すことはできません。したがって、副作用を実行したいときはいつでも、redux-saga効果(通常:callまたはfork)を介して副作用を発生させて実行する必要があります。 redux-saga効果を使用せずに直接実行すると、redux-sagaは副作用を調整できません。

考えてみると、redux-sagaジェネレーターは、モックを作成することなく完全にテスト可能です。また、物事を分離した状態に保つのに役立ちます。apiFetchFooがプロミスを返した場合、サガは同じように機能します。

27
Josep

Josepが指摘したように、awaitはジェネレーター内で使用できません。代わりに、 async function を使用する必要があります。また、これは非同期機能自体の制限であることに注意してください。 redux-sagaによるものではありません。

これを超えて、私はそれが 意識的な選択 redux-saga作者によるnotによる開発者の許可であることにも言及したかったasync/await関数としてsagasを表現します。

ジェネレーターはasync/awaitよりも強力で、 co-ordinating parallel tasks などのredux-sagaの高度な機能を使用できます。

さらに、sagaをジェネレーターとして表現することで、副作用を定義する単純なオブジェクトである Effects を定義できます。効果により、 サガのテストが非常に簡単 になります。

したがって、作業コードは問題ありませんが、sagaと非同期関数を混同しないことをお勧めします。

apiFetchFooを定義するだけで、リクエストへの応答で解決されるプロミスを返します。そして、これが起こると、あなたの物語はresultsから再開します。

 const apiFetchFoo = () =>
   fetch('foo')
     .then(res => res.json())
0

awaitは、asyncとして宣言されている関数内で常に機能します。 #thumbRule

async function fetchList () {
  let resp = await fetchApi([params]);
}
0
Venkat