Add Redux Saga to a React app

Redux is a package that manages state in React applications. I am assuming you know how to add Redux to a React app. If you don’t know, please check my blog post on how to add Redux to a React app.

Redux helps in streamlining data flow in the app. From event handlers, we create an action using action creators and dispatch the action with data to the store. The store is composed of reducers. These are functions which accepts the previous state and the dispatched action and generates a new state for the store. Before reducers process an action, the action passes through a series of middleware. Redux Saga is one such middleware.

CodeSandBox for Redux Saga

Connect configuration

The CodeSandBox has a simple React app. It fetches a list of users and displays those users in an unordered list. The connect configuration for the component is as follows.

function mapStateToProps(state) {
  return {
    users: state.users.list,
    loading: state.users.loading,
    error: state.users.error
  };
}

const dispatchProps = {
  onFetch: fetchUsers
};

export default connect(
  mapStateToProps,
  dispatchProps
)(Main);

From the Main component, we fetch the list of users by dispatching an action to the store.

componentDidMount() {
  this.props.onFetch();
}

Our action creator, fetchUsers, is quite simple.

export function fetchUsers() {
  return {
    type: ActionTypes.FetchUsers
  };
}

Saga Middleware

The real magic happens in the Saga middleware. We tell the Saga middleware to run a saga.

import { createStore, applyMiddleware } from "redux";
import rootReducer from "./rootReducer";
import createSagaMiddleware from "redux-saga";
import logger from "redux-logger";
import { usersSaga } from "./usersSaga";

const sagaMiddleware = createSagaMiddleware();
const store = createStore(rootReducer, applyMiddleware(sagaMiddleware, logger));

sagaMiddleware.run(usersSaga);

export default store;

So, what are these sagas? Saga is a generator function.

export function* usersSaga() {
  yield takeEvery(ActionTypes.FetchUsers, fetchUsers);
}

takeEvery is a function from Redux Saga. It listens for actions dispatched to the store. If FetchUsers action is dispatched to the store, the takeEvery function calls the fetchUsers function. fetchUsers is also a generator function.

function* fetchUsers(action) {
  yield put({
    type: ActionTypes.FetchUsersPending
  });
  try {
    const response = yield axios.get("https://reqres.in/api/users");
    yield put({
      type: ActionTypes.FetchUsersFulfilled,
      list: response.data.data
    });
  } catch (error) {
    yield put({
      type: ActionTypes.FetchUsersRejected,
      error
    });
  }
}

The fetchUsers starts by dispatching a new action, FetchUsersPending, to the store. Within Saga, the way to dispatch a function is by using the put function call. Then the function makes an API call to get a list of users. If the call is successful, the function dispatches a success action with the response data. If there is any exception, the function dispatches a failure action with the error message.

Redux Saga makes use of generator functions. So, the syntax may be a little difficult to understand. After writing a few generator functions, it becomes easy. There are only two functions in Redux Saga that we repeatedly make use of: takeEvery and put. takeEvery function watches for dispatched actions to the store. And if a matching action is found, triggers a generator function. From within a saga, we dispatch new actions using the put function.

Related Posts

Leave a Reply

Your email address will not be published.