redux-sagaまとめ
Kazuki Moriyama (森山 和樹)
Effect creators
take
指定されたパターンのアクションが発行されるまでこのtakeで止まる。
takeLatest
アクションを受けてsaga関数を発火する。
同じアクションでまだ実行中のプロセスがあれば殺す。
中身はforkなので処理をブロックしない。
以下で分かる通り無限にactionを待ち続けるところが他の多くのeffectと異なるところ。
const takeLatest = (patternOrChannel, saga, …args) => fork(function*() {
let lastTask
while (true) {
const action = yield take(patternOrChannel)
if (lastTask) {
yield cancel(lastTask) // cancel is no-op if the task has already terminated
}
lastTask = yield fork(saga, ...args.concat(action))
}
})
race
複数のeffectを受けて、どれかが終了したら他effectも中断する。
これを利用して非同期処理のキャンセルを実装できる。
import { take, call, race } from 'redux-saga/effects'
import fetchUsers from './path/to/fetchUsers'
function* fetchUsersSaga() {
const [response, cancel] = yield race([
call(fetchUsers),
take(CANCEL_FETCH) // CANCEL_FETCHがdispatchされるとfetchUsersがキャンセルされる
])
}
all
複数のeffectを並列実行し、それらすべての完了を待つ。
call
渡された関数と引数を実行し、その場で待つ。
fork
callと同様に関数を実行するが、処理を待たない。
raceの中でforkは使用してはいけない。
// DO NOT DO THIS. The fork effect always win the race immediately.
yield race([
fork(someSaga),
take('SOME-ACTION'),
somePromise,
])
delay
yield delay(mills)
でmillsミリ秒待つ
sagaのforkモデル
非同期タスクをforkさせる方法として
- Attached fork
- Detached fork
の2つがある。
Effectをネストさせるとき親と子の関係が違ってくる。
Attached fork
fork
メソッドを使用して作成する- 親はすべての子の完了を待つ
- 一つの子がエラーを吐くと兄弟と親も殺す
- 親がキャンセルされると子も全てキャンセルされる
Detached fork
spawn
メソッドを使用して作成する- 親と子になんのつながりもない
- 完了、エラー、キャンセルが親と子のいずれで起ころうともう片方になんの影響も及ぼさない
sagaレシピ
polling
必要なアクション
- polling start
- polling resultを流すアクション
- polling stop
必要なジェネレータ関数
- 無限にstartを監視し続けるwatcher function
- 無限にpollingを続けるworker function
pollingの流れ
- startを検知したwatcherが
take(stop)
とworkerをrace
で走らせる - workerは無限にpollingし、結果を受け取ると通知する
- stopが発行されると
race
が終了しpollingが終了する
import { race, take, call } from 'redux-saga/effects'
/* Worker Function */
function* pollTask() {
while (true) {
try {
// Fetching posts at regular interval 4 seconds.
const posts = yield call(httpGet, 'posts');
yield put({
type: 'ON_POST_FETCH_SUCCESS',
posts: posts
});
yield call(delay, 4000);
} catch (err) {
yield put({
type: 'ON_POST_FETCH_ERROR',
message: err.message
});
// Once the polling has encountered an error,
// it should be stopped immediately
yield put({ type: 'STOP_WATCHER_TASK', err });
}
}
}
/* Watcher Function */
function* pollTaskWatcher() {
while (true) {
yield take('START_WATCHER_TASK')
yield race( [call(pollTask), take('STOP_WATCHER_TASK')] )
}
}