前書き
この記事は redux-saga の使い方はあまり記述していません。
あくまで使ってみたら便利だった体験談を備忘録がわりに書き留めたものです。
連続した非同期通信ケース
そもそも連続した非同期通信が走る状況ってどんなときってことなんですが
下のケースが例として挙げられます。
- ニュース一覧リストをレイジーロードする時
- 料金取得APIなど、フロント側のInput要素のChangeイベントごとにAPIを叩く時
- 商品リストの「次へ」ボタンをユーザーが連打する時
これらのAPI通信が走っている際、画面にローディングを付けたいと思うかもしれません。
その際、ローディングを終えるタイミングは連続したAPIコールの最後の処理が終わった時ですよね。
簡単に今まで書いていた処理を記述してみました。
// セッションの宣言
const session = new Date().getTime()
// ローディング開始アクションにセッションを渡す
dispatch<LoadStart>({
type: ActionTypes.LoadStart,
payload: { session }
})
try {
// 非同期通信開始
const resp = await getHogeApiResponse(requestParam)
// 通信成功時、payloadにセッション情報も含める
dispatch<LoadEnd>({
type: ActionTypes.LoadEnd,
payload: { data: resp, session }
})
} catch (e) {
// 通信失敗時、payloadにセッション情報も含める
dispatch<LoadEnd>({
type: ActionTypes.LoadEnd,
payload: { session }
})
}
- セッションを宣言し、非同期通信をする直前でステートにセッションを登録
- APIをコールし、通信成功・失敗に関わらず再度セッションを渡す
- ステートのセッションを比較し、セッションが異なれば、他にAPIコールが行われているためローディングを続行
- ステートのセッションを比較し、同一だったらローディング終了
という流れです。
この処理を非同期通信部分に1個1個書いていく必要があるため、手間に感じていました。
redux-saga を使った場合
function* fetchHoge(action) {
try {
// 非同期通信開始、callの第一引数でAPI通信関数、第二引数で通信処理の引数を指定
const resp = yield call(getHogeApiResponse, {
requestParam: action.payload
})
// 通信成功時
yield put<FetchHogeSucceeded>({
type: ActionTypes.FetchHogeSucceeded,
payload: resp
})
} catch (e) {
// 通信失敗時
yield put<FetchHogeFailed>({
type: ActionTypes.FetchHogeFailed
})
}
}
export function* sagas() {
// ActionTypes.FetchHogeRequestedを監視
// このアクションが呼ばれたらfetchHogeを起動する。
yield takeLatest(ActionTypes.FetchHogeRequested, fetchHoge)
}
redux-saga本来の書き方が特徴的であるため、前述したものと比べて冗長に見えますが
セッションに当たる部分を担っているのは下のほうに記述してある takeLatest
指定のみです。
takeLatestの動作
もしレスポンス待ちの状態で USER_FETCH_REQUESTED を受け取った場合、
待ち状態のリクエストはキャンセルされて最後の1つだけが実行されます。
公式だとこうなっていますね。
連打される可能性のある非同期通信処理が10個あったとしても10回takeLatest指定してあげれば良いわけです。
とても楽チン。
逆にすべて並列で処理したい場合はtakeEveryが使えます。
まとめ
今回のことでredux-sagaが最高! と断言するわけではありません。
しっかりかけますが、記述も独特で若干冗長になりやすいです。
ただ、非同期通信処理をStore内で切り分けられるので設計を整理しやすく、好印象でした。
個人的には
簡単な非同期通信処理のみ扱う際は redux-thunk
しっかりと非同期通信処理を管理したい場合は redux-saga
という印象です。
また次の機会にも使っていこうと思います。
ここまでお読みいただきありがとうございました。