Getting started with Redux: Redux-saga with React

Dina Elghndour
Oct 17, 2019 · 4 min read

We have a series of articles about Getting started with Redux, the links at the end.


Why should we use middleware?

  1. If we need to communicate with an external API in react, the data fetching can take a while because the promise needs to resolve. Once the promise resolves, you want to dispatch a delayed action to update the state in the Redux store
  2. the middleware intercepts the action object before Reducer receives it and gives the functionality to perform additional actions.
  3. That’s where asynchronous action libraries such as Redux Saga, Redux Thunk come into play.

How it works?

[ Action ] <-> [ Middleware ] <-> [ Dispatcher ]
  • Middleware is basically a function → that accepts the store → which is expected to return a function → that accepts the next function, and so on.

Now, when creating a new react-redux app, you’ll generally be guided to use redux-thunk or redux-saga to handle asynchronous actions let’s talk about differences between them.


Difference between redux-thunk and redux-saga

  • In our story we will talk about redux-saga in details.

What is Saga?

  • Saga is a long running process (initialize once, runs for a while).
  • waits for events (action).
  • responds to actions with new actions, side effects.

Installation:

  1. install redux-saga
npm install --save redux-saga

2. Connect your sagas to store

import { createStore, applyMiddleware } from 'redux';import createSagaMiddleware from 'redux-saga';import rootReducer from '../reducers';import rootSaga from '../sagas';const saga = createSagaMiddleware();const store = createStore(rootReducer,applyMiddleware(saga));saga.run(rootSaga);export default store;

3. In your API file “./apis/posts.js”

import axios from 'axios';const axiosInstance = axios.create({baseURL: 'http://localhost:3001'});const getPosts = async () => await axiosInstance.get(`/posts`);export default { getPosts };

4. In your typs file “./Types.js”

export const FETCH_POSTS = 'FETCH_POSTS';
export const FETCH_POSTS_REQUEST = 'FETCH_POSTS_REQUEST';

5. In your action file “./action/index.js”

import  * as actionTypes from './Types';export const fetchPosts = posts => ({  type: actionTypes.FETCH_POSTS,  payload: posts,});export const fetchPostsReq = () => ({ 
type: actionTypes.FETCH_POSTS_REQUEST });

6. In reducers file “./reducers/posts.js

import  * as actionTypes from './Types';export default (state = {}, action) => { switch (action.type) {case actionTypes.FETCH_POSTS:     return { ...state, ...action.payload };   default:     return state; }
}
  • Don’t forget to combine your reducers.

7. In your root sagas file “./sagas/index.js”

import { takeEvery } from 'redux-saga/effects';import  * as actionTypes from './Types';import { fetchPostsSaga } from './posts';export function* watchAll() {  yield takeEvery(actionTypes.FETCH_POSTS_REQUEST, fetchPostsSaga);}

takeEvery: allows multiple instances of these sagas to run at the same time.

takeLatest: if you dispatch the action before the previous API call finishes, it will stop that call and return only the latest one.

8. In saga file for posts “./sagas/posts.js”

import { put, call } from 'redux-saga/effects';import { fetchPosts } from '../actions';import API from '../apis/posts';export function* fetchPostsSaga() {try {  const response = yield call(API.getPosts);  yield put(fetchPosts(response.data));  } catch (error) {    console.log(error);  }}

Sagas effects

Put: it dispatching an action for the reducer to handle the response.

Call: call a ‘API’ function that executes a server call and returns a promise, which will hold the response content when successful.

Generators functions: The function* declaration (function keyword followed by an asterisk) defines a generator function, which returns a Generator object. This method will return the next element in the sequence.

Yield: The keyword yield is used to suspend and resume a generating function.

9. Then all what you need is to call the action in you component.

import React, { Component } from 'react';import { connect } from 'react-redux';import { fetchPostsReq } from './actions';import store from './Store';class PostsList extends Component {componentDidMount() {  this.props.fetchPostsReq();} render() {   return <h1> Home page <h1> }}const mapStateToProps = state => {return { posts: state.posts};};export default connect(mapStateToProps,{ fetchPostsReq})(PostsList);

Summary

  1. Redux-saga is a powerful tool that cleans up your code.
  2. It is allows for complex manipulations of async flow.
  3. It would be very difficult to accomplish the same things without it, so it is definitely worth the time to learn.

We have a series of articles about Redux:


Thank you for reading, if you have any comments let me know, please :)

That’s all for today see you soon in my next story …👋

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade