Pause in Redux Saga


Your code running too fast? Do you just want a timing offset for some reason? If you have a long-running, complicated action that you're running already, it's likely you're using the fantastic redux-saga. Here's a way to pause execution with a redux-saga-managed action.

Write the Pause Function

First let's write the pause function. This function has to do nothing more than hang out for a while. The easiest way to do nothing is to call setTimeout. Let's do that. To make our async function work well in the context of redux-saga, we'll return a Promise that takes a moment to resolve:

export default function pause(delay) {
  return new Promise(resolve => {
    setTimeout(_ => {
      resolve()
    }, delay.millis)
  })
}

This function now acts like any other async function that your saga might call, such as an api call.

Calling Pause

For a quick scenario, let's say that we have an action around alerting, where we want to dismiss all alert dialogs from our UI. Each alert will animate out when it is dismissed. We want a timing offset between each that will make them look staggered as they animate off-screen. To accomplish this, we'll pause for increasingly-long amounts of time before dismissing each one:

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

import * as actions from './actions'
import pause from '../common/pause'

const pauseStepDefault = 700

export function* dismissAll(alerts, pauseStep = pauseStepDefault) {
  const ids = alerts.map(a => a.id)
  for (let i = 0; i < ids.length; ++i) {
    yield call(pause, { millis: pauseStep * (i + 1) })
    yield put(actions.dismissAlert(ids[i]))
  }
}

Note that the pause function that we wrote is simply called with the call effects helper that we're used to using in redux-saga. The actions.dismissAlert function is implemented elsewhere and not necessarily germane to this pattern. This implementation requires your alerts to have an id property. Also note the use of the for statement as opposed to a forEach with anonymous function. This is done to simply and avoid nesting generator functions.

Pretty cool, right? Who knew pausing to take it all in could be so rewarding? #slowdown

What are some other cool async actions that you've implemented with redux or redux-saga beyond regular 'ol api calls?