Redux-Saga
An intuitive Redux side effect manager.
Easy to manage, easy to test, and executes efficiently.
Asynchronous
ES6 generators make asynchronous flows easy to read, write, and test. Create complex side effects without getting bogged down by the details.
Composition-focused
Sagas enable numerous approaches to tackling parallel execution, task concurrency, task racing, task cancellation, and more. Keep total control over the flow of your code.
Easy To Test
Assert results at each step of a generator or for a saga as a whole. Either way, side effect testing is quick, concise, and painless, as testing should be.
Example Usage
- 1. Dispatch an action
- 2. Initiate a side effect
- 3. Connect to the store
- 4. Connect to the store (new version)
Suppose we have a UI to fetch some user data from a remote server when a button is clicked. (For brevity, we'll just show the action triggering code.)
class UserComponent extends React.Component {...onSomeButtonClicked() {const { userId, dispatch } = this.propsdispatch({type: 'USER_FETCH_REQUESTED', payload: {userId}})}...}
The component dispatches a plain object action to the store. We'll create a Saga that watches for all USER_FETCH_REQUESTED
actions and triggers an API call to fetch the user data.
import { call, put, takeEvery, takeLatest } from 'redux-saga/effects'import Api from '...'// Worker saga will be fired on USER_FETCH_REQUESTED actionsfunction* fetchUser(action) {try {const user = yield call(Api.fetchUser, action.payload.userId);yield put({type: "USER_FETCH_SUCCEEDED", user: user});} catch (e) {yield put({type: "USER_FETCH_FAILED", message: e.message});}}// Starts fetchUser on each dispatched USER_FETCH_REQUESTED action// Allows concurrent fetches of userfunction* mySaga() {yield takeEvery("USER_FETCH_REQUESTED", fetchUser);}
To run our Saga, we have to connect it to the Redux store using the redux-saga
middleware.
import { createStore, applyMiddleware } from 'redux'import createSagaMiddleware from 'redux-saga'import reducer from './reducers'import mySaga from './sagas'// Create the saga middlewareconst sagaMiddleware = createSagaMiddleware()// Mount it on the Storeconst store = createStore(reducer,applyMiddleware(sagaMiddleware))// Then run the sagasagaMiddleware.run(mySaga)// Render the application
This is the new version of running saga by using configureStore from reduxjs/toolkit
instead of createStore from Redux
.
import { configureStore } from '@reduxjs/toolkit'import createSagaMiddleware from 'redux-saga'import reducer from './reducers'import mySaga from './sagas'// Create the saga middlewareconst sagaMiddleware = createSagaMiddleware()const middleware = [sagaMiddleware]// Mount it on the Storeconst store = configureStore({reducer,middleware: (getDefaultMiddleware) =>getDefaultMiddleware().concat(middleware),})// Then run the sagasagaMiddleware.run(mySaga)// Render the application
Sponsors
Become a sponsor and have your logo shown below and on Github with a link to your site. Become a sponsor