Skip to main content

Using Saga Helpers

redux-saga provides some helper effects wrapping internal functions to spawn tasks when some specific actions are dispatched to the Store.

The helper functions are built on top of the lower level API. In the advanced section, we'll see how those functions can be implemented.

The first function, takeEvery is the most familiar and provides a behavior similar to redux-thunk.

Let's illustrate with the common AJAX example. On each click on a Fetch button we dispatch a FETCH_REQUESTED action. We want to handle this action by launching a task that will fetch some data from the server.

First we create the task that will perform the asynchronous action:

import { call, put } from 'redux-saga/effects'
import Api from './path/to/api'

export function* fetchData(action) {
try {
const data = yield call(Api.fetchUser, action.payload.url)
yield put({ type: 'FETCH_SUCCEEDED', data })
} catch (error) {
yield put({ type: 'FETCH_FAILED', error })
}
}

To launch the above task on each FETCH_REQUESTED action:

import { takeEvery } from 'redux-saga/effects'

function* watchFetchData() {
yield takeEvery('FETCH_REQUESTED', fetchData)
}

In the above example, takeEvery allows multiple fetchData instances to be started concurrently. At a given moment, we can start a new fetchData task while there are still one or more previous fetchData tasks which have not yet terminated.

If we want to only get the response of the latest request fired (e.g. to always display the latest version of data) we can use the takeLatest helper:

import { takeLatest } from 'redux-saga/effects'

function* watchFetchData() {
yield takeLatest('FETCH_REQUESTED', fetchData)
}

Unlike takeEvery, takeLatest allows only one fetchData task to run at any moment. And it will be the latest started task. If a previous task is still running when another fetchData task is started, the previous task will be automatically cancelled.

If you have multiple Sagas watching for different actions, you can create multiple watchers with those built-in helpers, which will behave like there was fork used to spawn them (we'll talk about fork later. For now, consider it to be an Effect that allows us to start multiple sagas in the background).

For example:

import { takeEvery } from 'redux-saga/effects'

// FETCH_USERS
function* fetchUsers(action) { ... }

// CREATE_USER
function* createUser(action) { ... }

// use them in parallel
export default function* rootSaga() {
yield takeEvery('FETCH_USERS', fetchUsers)
yield takeEvery('CREATE_USER', createUser)
}