Permalink
55 lines (41 sloc) 1.56 KB

Starting a race between multiple Effects

Sometimes we start multiple tasks in parallel but we don't want to wait for all of them, we just need to get the winner: the first one that resolves (or rejects). The race Effect offers a way of triggering a race between multiple Effects.

The following sample shows a task that triggers a remote fetch request, and constrains the response within a 1 second timeout.

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

function* fetchPostsWithTimeout() {
  const {posts, timeout} = yield race({
    posts: call(fetchApi, '/posts'),
    timeout: delay(1000)
  })

  if (posts)
    yield put({type: 'POSTS_RECEIVED', posts})
  else
    yield put({type: 'TIMEOUT_ERROR'})
}

Another useful feature of race is that it automatically cancels the loser Effects. For example, suppose we have 2 UI buttons:

  • The first starts a task in the background that runs in an endless loop while (true) (e.g. syncing some data with the server each x seconds).

  • Once the background task is started, we enable a second button which will cancel the task

import { race, take, call } from 'redux-saga/effects'

function* backgroundTask() {
  while (true) { ... }
}

function* watchStartBackgroundTask() {
  while (true) {
    yield take('START_BACKGROUND_TASK')
    yield race({
      task: call(backgroundTask),
      cancel: take('CANCEL_TASK')
    })
  }
}

In the case a CANCEL_TASK action is dispatched, the race Effect will automatically cancel backgroundTask by throwing a cancellation error inside it.