Close Menu
Soshace Digital Blog

    Subscribe to Updates

    Get The Latest News, Updates, And Amazing Offers

    What's Hot
    Flask

    Email Support with Flask

    Programming

    3. Express.js Lessons. Templating with EJS: Layout, Block, Partials

    Wiki

    Роль Менеджера Продуктов

    Important Pages:
    • Home
    • About
    • Services
    • Contact Us
    • Privacy Policy
    • Terms & Conditions
    Facebook X (Twitter) Instagram LinkedIn YouTube
    Today's Picks:
    • Scaling Success: Monitoring Indexation of Programmatic SEO Content
    • Leveraging Influencers: Key Drivers in New Product Launches
    • How Privacy-First Marketing Will Transform the Industry Landscape
    • The Impact of Social Proof on Thought Leadership Marketing
    • Balancing Value-Driven Content and Promotional Messaging Strategies
    • Top Influencer Marketing Platforms to Explore in 2025
    • Emerging Trends in Marketing Automation and AI Tools for 2023
    • Strategies to Mitigate Duplicate Content in Programmatic SEO
    Sunday, September 28
    Facebook X (Twitter) Instagram LinkedIn YouTube
    Soshace Digital Blog
    • Home
    • About
    • Services
    • Contact Us
    • Privacy Policy
    • Terms & Conditions
    Services
    • SaaS & Tech

      Maximizing Efficiency: How SaaS Lowers IT Infrastructure Costs

      August 27, 2025

      Navigating Tomorrow: Innovations Shaping the Future of SaaS

      August 27, 2025

      Maximizing Impact: Strategies for SaaS & Technology Marketing

      August 27, 2025
    • AI & Automation

      Enhancing Customer Feedback Analysis Through AI Innovations

      August 27, 2025

      Navigating the Impact of AI on SEO and Search Rankings

      August 27, 2025

      5 Automation Hacks Every Home Service Business Needs to Know

      May 3, 2025
    • Finance & Fintech

      Critical Missteps in Finance Marketing: What to Avoid

      August 27, 2025

      Analyzing Future Fintech Marketing Trends: Insights Ahead

      August 27, 2025

      Navigating the Complex Landscape of Finance and Fintech Marketing

      August 27, 2025
    • Legal & Compliance

      Exploring Thought Leadership’s Impact on Legal Marketing

      August 27, 2025

      Maximizing LinkedIn: Strategies for Legal and Compliance Marketing

      August 27, 2025

      Why Transparency Matters in Legal Advertising Practices

      August 27, 2025
    • Medical Marketing

      Enhancing Online Reputation Management in Hospitals: A Guide

      August 27, 2025

      Analyzing Emerging Trends in Health and Medical Marketing

      August 27, 2025

      Exploring Innovative Content Ideas for Wellness Blogs and Clinics

      August 27, 2025
    • E-commerce & Retail

      Strategic Seasonal Campaign Concepts for Online and Retail Markets

      August 27, 2025

      Emerging Trends in E-commerce and Retail Marketing Strategies

      August 27, 2025

      Maximizing Revenue: The Advantages of Affiliate Marketing for E-Commerce

      August 27, 2025
    • Influencer & Community

      Leveraging Influencers: Key Drivers in New Product Launches

      August 27, 2025

      Top Influencer Marketing Platforms to Explore in 2025

      August 27, 2025

      Key Strategies for Successful Influencer Partnership Negotiations

      August 27, 2025
    • Content & Leadership

      The Impact of Social Proof on Thought Leadership Marketing

      August 27, 2025

      Balancing Value-Driven Content and Promotional Messaging Strategies

      August 27, 2025

      Analyzing Storytelling’s Impact on Content Marketing Effectiveness

      August 27, 2025
    • SEO & Analytics

      Scaling Success: Monitoring Indexation of Programmatic SEO Content

      August 27, 2025

      Strategies to Mitigate Duplicate Content in Programmatic SEO

      August 27, 2025

      Effective Data Visualization Techniques for SEO Reporting

      August 27, 2025
    • Marketing Trends

      How Privacy-First Marketing Will Transform the Industry Landscape

      August 27, 2025

      Emerging Trends in Marketing Automation and AI Tools for 2023

      August 27, 2025

      Maximizing ROI: Key Trends in Paid Social Advertising

      August 27, 2025
    Soshace Digital Blog
    Blog / JavaScript / React / Handling Side Effects in Redux: Redux-Saga
    JavaScript

    Handling Side Effects in Redux: Redux-Saga

    Adaware OgheneroBy Adaware OgheneroNovember 29, 2019Updated:December 24, 2019No Comments16 Mins Read
    Facebook Twitter Pinterest Telegram LinkedIn Tumblr Email Reddit
    Handling Side Effects in Redux: Redux-Saga
    Handling Side Effects in Redux Redux-Saga Outside
    Share
    Facebook Twitter LinkedIn Pinterest Email Copy Link
    Handling Side Effects in Redux Redux-Saga
    Handling Side Effects in Redux Redux-Saga

    In this article you will learn the following:

    1. How side-effects are handled in Redux
    2. What Redux-saga is
    3. What generator functions are
    4. How to handle side-effects using redux-saga while building a simple application

    If you have used Redux in a React project before, there gets a point, where you will have to handle side-effects(asynchronous) like API calls or setting timeout and intervals, because these are required when building features of a “complex web application.”

    The Redux architecture is meant to provide predictable state change, meaning it takes an action and state then returns a new state. This architecture doesn’t provide any built-in means for handling asynchronous changes to the Redux state tree.

    Redux flow
    Redux flow

    So where can we put our side-effects in the Redux flow? We could handle our side-effects at the component level then dispatch an action with the resolved result of the side effects.

    class App extends React.Component {
    
      fetchUser=(id)=>{
        Api.fetchUser().then(res =>{
          let user = res.user
          dispatch({type: "USER_FETCH_SUCCEEDED", user: user})
        })
        .catch(err =>{
          dispatch({type: "USER_FETCH_FAILED", message: err.message})
        })
      }
    
      render() {
        const {id} = this.state
          return (
              <div>
                  <button onClick={()=>this.fetchUser(id)}>Fetch User</button>
              </div>
          );
      }
    }

    But the problem with this approach is that in large applications, you might have multiple components that want to fetch a user, so you might have duplicate logic, and this becomes difficult to maintain.

    Another option is to move the async logic(side-effect) to the action creators. Usually, in redux, action creators are functions that return an action; a plain object that must have a `type` property, at least.

    function fetchData(param) {
    	return {
    		type: "FETCH_DATA",
    		payload: param
    	};
    }

    We can use a middleware like redux-thunk which allows you to dispatch functions/promises and write async logic in your action creators. What the middleware does is look at every action dispatched, if it is a function, it calls that function and pass two arguments; the store’s dispatch method, which can be used to dispatch plain action objects when the asynchronous code has failed or succeeded and the store’s getState method is passed to it so the store can be read and used in the action creators.

    class App extends React.Component {
    	render() {
    		const { id } = this.state;
    		const { dispatch } = this.props;
    		return (
    			<div>
    				<button onClick={() => dispatch(requestUser(id))}>Fetch User</button>
    			</div>
    		);
    	}
    }
    
    // action creator(thunk)
    
    function requestUser(id) {
    	return function(dispatch) {
    		return Api.fetchUser()
    			.then(res => {
    				let user = res.user;
    				dispatch({ type: "USER_FETCH_SUCCEEDED", user: user });
    			})
    			.catch(err => {
    				dispatch({ type: "USER_FETCH_FAILED", message: err.message });
    			});
    	};
    }

    Here, we have the fetch user API call in the action creator, so any component that needs to fetch a user can dispatch the `requestUser()` action instead of duplicating logic.

    Using a middleware like redux-thunk has its benefits:

    • The business logic is not tightly coupled to the UI components so it can be reused by components.
    • It is easy to learn unlike redux-saga(which we will be covering later in this article) because you don’t need to learn new JavaScript concepts to use it.

    It also has some disadvantages:

    • It can become difficult to read and understand when you start dealing with complex async login in complex applications.
    • It doesn’t provide any way to handle advanced async operations like cancellation and debouncing.

    Despite its negatives, Redux-thunk remains the most used redux middleware for handling side-effects, and it works for most use-cases, but it doesn’t work in complex applications where you might want to cancel an API request after an action has been dispatched, or you want to debounce a function call.

    This complex situation is where a middleware like redux-saga thrive, it helps you handle these easily using special function called effects provided by redux-saga.

    Redux-saga also allows us to write async code in a declarative manner hence it is more readable and easier to test. Now we will do a deep dive into Es6 generators and Redux-saga, then we will build a trivial application using redux-saga middleware.

    Redux-saga

    Redux-saga is built on the concept of generators which was introduced as part of the ECMAScript 2015 module. Generators are a powerful concept, which you might not use every day in programming but its strengths were leveraged to create Redux-saga, which then gives users the ability to write asynchronous code in a synchronous manner, thereby eliminating problems with callbacks(callback hell), as well as helps to run side-effects in parallel, cancel them, etc. Both of which are difficult or impossible using redux-thunk.

    What is a Generator function?

    A generator function is a function that can be paused and later resumed while retaining its variable bindings(context). It is denoted with an asterisk in front of the function keyword.

    function* myFunction() {
    	//
    	//
    }

    Unlike a normal function in JavaScript, which runs until it gets to a `return` statement or until it has completely executed, generators run until it gets to a `yield` or `return` statement.

    When a generator function is invoked, it doesn’t execute the function body immediately, instead — it returns an iterable/generator object that can be iterated or looped through using the iterator’s `next()` method or a `for..of loop`.

    function* gen() {
    	yield 1;
    	yield 2;
    	yield 3;
    	yield 4;
    }
    
    let myGenerator = gen();
    
    console.log(myGenerator.next()); //{value: 1, done: false}
    console.log(myGenerator.next()); //{value: 2, done: false}
    console.log(myGenerator.next()); //{value: 3, done: false}
    console.log(myGenerator.next()); //{value: 4, done: false}
    console.log(myGenerator.next()); // {value: undefined, done: true}

    Each iteration is defined by the `yield` keyword, so when you execute a generator function and call its `next()` method, it runs the function until it encounters the first `yield` statement, then it pauses and returns an object containing a `value` and `done` property;`value` is anything on the right-hand side of the keyword `yield`, it can be a value(integer, string), function, object, promise, etc., while the `done` property is a `boolean,` which indicates if it is done iterating thorough the iterable.

    So how does this fit with redux-saga? In redux-saga, we move our side-effects from the action-creators to generator functions called sagas. What redux-saga does is to run our sagas(generator functions) and provide methods for handling the side-effects and also interacting with the redux store. redux-saga executes our generator functions(sagas) containing the side-effects then handles the process of calling the `next()` on the generator object internally.

    Read More:  Top 9 Web Components UI Libraries

    Below is a simple saga that makes a cup of coffee after 10 mins:

    const delay = ms => new Promise(res => setTimeout(res, ms));
    
    function* makeCoffee() {
    	yield take({ type: "REQUEST_COFFEE" });
    	yield delay(10000);
    	yield put({ type: "COFFEE_DONE" });
    }

    This is just a simple snippet of a saga that yields objects to the redux-saga middleware. The yielded objects are like instructions to be interpreted by the middleware. You might have noticed functions `take`, `delay` and `put` in the saga above, these are helper functions provided by redux-saga. We will walk through each line of the saga to understand what it does, then I will show the redux-thunk implementation.

    The first line in the example above:

    yield take({type:'REQUEST_COFFEE'})

    `take` is an effect that instructs the redux-saga middleware to wait for the `REQUEST_COFFEE` action to be dispatched by the store before it resumes execution of the generator function. So this function is paused until someone dispatches a `REQUEST_COFFEE` action; then when it is dispatched, it resumes execution and executes it until the next yield.

    yield delay(60000)

    `delay` is a function that returns a promise so when a promise is yielded to the redux-saga middleware, the middleware pauses the saga until the promise is resolved then execution resumes after 60 seconds. As I said earlier anything can be yielded by a generator function, it can be a function, promise, or value. But what redux-saga does here is that when it is yielded a promise, it has to wait for it to be resolved. This is quite similar to the async await way of handling promises.
    So after 60 seconds, execution resumes until it gets to the final `yield`

    yield put({type:'COFFEE_DONE'})

    `put` is another effect provided by redux-saga which can be used to dispatch actions in a saga. So this instructs the middleware to dispatch an action `COFFEE_DONE` to the store.

    `put` and `take` are examples of helpers effects provided by redux-saga. Effects are plain JavaScript objects which contain specific instructions to be carried out by the middleware.

    Effects are divided into two groups in redux-saga, blocking call and non-blocking call.

    A blocking call means that the saga yielded an effect and will wait for the outcome of its execution before resuming execution inside the generator function.

    A non-blocking call means the saga will resume immediately after yielding the effect.

    Blocking vs Non-blocking calls
    Blocking vs Non-blocking calls

    There are more helper effects, but these are some of them. You can check out the redux-saga docs for all of them.

    Demo Application

    Now that we have a little knowledge of generators and redux-saga, we will be building a simple application that calls the Jikan API, an unofficial API for MyAnimeList, to get the top animes airing and also search for your favorite anime.

    This is what the application will look like

    Live Demo of the application

    Folder Structure

    └───src
        │   Api.js
        │   App.js
        │   App.module.css
        │   constants.js
        │   index.css
        │   index.js
        │   rootSaga.js
        │   store.js
        │
        ├───components
        │       AnimeList.jsx
        │       AnimeList.module.css
        │       TopAnimes.jsx
        │       TopAnimes.module.css
        │
        └───ducks
                actions.js
                reducer.js
                sagas.js
                types.js

    index.js

    import React from "react";
    import ReactDOM from "react-dom";
    import { Provider } from "react-redux";
    import store from "./store";
    import "./index.css";
    import App from "./App";
    
    ReactDOM.render(
    	<Provider store={store}>
    		<App />
    	</Provider>,
    	document.getElementById("root")
    );

    This is the entry point of our application. In this file, we wrapper the `App` component with the react-redux `Provider,` which gives the `App` component and any component below it in the component tree access to the redux store if it is wrapped using `connect()` function.

    store.js

    import { applyMiddleware, createStore, compose } from "redux";
    import createSagaMiddleware from "redux-saga";
    import rootSaga from "./ducks/sagas";
    import { animeReducer } from "./ducks/reducer";
    
    const composeEnhancers =
    	(window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ &&
    		window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
    			trace: true,
    			traceLimit: 25
    		})) ||
    	compose;
    
    const sagaMiddleware = createSagaMiddleware();
    
    const store = createStore(
    	animeReducer,
    	composeEnhancers(applyMiddleware(sagaMiddleware))
    );
    
    sagaMiddleware.run(rootSaga);
    
    export default store;

    In this file, we set up the redux-store, the redux-saga middleware, and the redux-devtools.

    const sagaMiddleware = createSagaMiddleware();
    ```
    
    The line above creates the saga middleware
    
    ```js
    const store = createStore(
    	animeReducer,
    	composeEnhancers(applyMiddleware(sagaMiddleware))
    );

    This line creates the store using redux `createStore` function, the first argument passed to it is the root reducer while the second argument is the enhancer, and it composes the redux-devtools and the saga middleware together.

    sagaMiddleware.run(rootSaga);

    This line above dynamically runs the sagas, and it takes a saga as an argument.

    App.js

    import React, { useEffect, useState } from "react";
    import { connect, useDispatch } from "react-redux";
    import AnimeList from "./components/AnimeList";
    import TopAnimes from "./components/TopAnimes";
    import styles from "./App.module.css";
    import { requestTopAnime, requestSearchAnime } from "./ducks/actions";
    import { getTopAnimesResults, getSearchResults } from "./ducks/reducer";
    
    function App(props) {
    	const [query, setQuery] = useState("");
    	const dispatch = useDispatch();
    
    	const fetchQuery = () => {
    		dispatch(requestSearchAnime(query));
    	};
    
    	useEffect(() => {
    		dispatch(requestTopAnime());
    		dispatch(requestSearchAnime());
    	}, [dispatch]);
    
    	return (
    		<>
    			<header className={styles.header}>
    				<div className={styles.logo}>Anime Viewer</div>
    				<nav className={styles.nav}>
    					<input
    						type="text"
    						className={styles.searchField}
    						value={query}
    						onChange={e => setQuery(e.target.value)}
    					/>
    					<button className={styles.searchBtn} onClick={fetchQuery}>
    						Search
    					</button>
    				</nav>
    			</header>
    			<main className={styles.content}>
    				<AnimeList animes={props.animes} />
    				<TopAnimes topAnimes={props.topAnimes} />
    			</main>
    		</>
    	);
    }
    
    const mapStateToProps = state => ({
    	topAnimes: getTopAnimesResults(state),
    	animes: getSearchResults(state)
    });
    
    export default connect(mapStateToProps, null)(App);

    This is the parent component of our application, when it is about to mount it dispatches two actions to the redux store; `requestTopAnime` which requests the top airing animes and `requestSearchAnime()` which requests the top animes of all time. `requetSearchAnime()` is also used to search for animes if a query argument is passed to it.

    This component has a search field so you can search for your favorite anime and two other components `AnimeList` and `TopAnimes`.

    AnimeList.js

    const AnimeList = props => {
    	return (
    		<section className={styles.listContainer}>
    			{props.animes.map(anime => {
    				return (
    					<div key={anime.mal_id} className={styles.anime}>
    						<img src={anime.image_url} alt={anime.title} />
    						<div className={styles.overlay}>
    							<p className={styles.title}>{anime.title}</p>
    							<p className={styles.rating}>
    								<span>Score:</span> {anime.score}
    							</p>
    						</div>
    					</div>
    				);
    			})}
    		</section>
    	);
    };
    
    const mapStateToProps = state => ({
    	animes: getSearchResults(state)
    });
    
    export default connect(mapStateToProps)(AnimeList);

    This component displays the search results if there is a query, or the best animes if the query field is empty. We connect this component to the Redux store using react-redux `connect()` function. Also, we have a state selector `getSearchResults` that is used to select the part of the state needed in this component.

    TopAnimes.js

    const TopAnimes = props => {
    	return (
    		<aside>
    			<p>Top airing anime</p>
    			<div className={styles.rankContainer}>
    				{props.topAnimes.slice(0, 20).map(item => {
    					return (
    						<div className={styles.rankItem} key={item.mal_id}>
    							<img
    								src={item.image_url}
    								alt={item.title}
    								className={styles.rankImage}
    								height="70"
    								width="50"
    							/>
    							<div className={styles.rankDetails}>
    								<p>{item.title}</p>
    								<p>Episode: {item.episodes}</p>
    							</div>
    						</div>
    					);
    				})}
    			</div>
    		</aside>
    	);
    };
    
    const mapStateToProps = state => ({
    	topAnimes: getTopAnimesResults(state)
    });
    
    export default connect(mapStateToProps)(TopAnimes);

    It is similar to the `AnimeList` component, but it renders the lists of top animes airing. It has a state selector `getTopAnimesResults` for selecting the relevant state it needs.

    Read More:  Guidelines for Building Accessible Web Applications

    actions.js

    import * as types from "./types";
    
    export const requestSearchAnime = payload => ({
    	type: types.SEARCH_REQUEST,
    	payload: payload
    });
    
    export const fulfilledSearchAnime = payload => ({
    	type: types.SEARCH_SUCCESS,
    	payload: payload
    });
    
    export const failedSearchAnime = payload => ({
    	type: types.SEARCH_FAILURE,
    	payload: payload
    });
    
    export const requestTopAnime = payload => ({
    	type: types.TOPANIME_REQUEST,
    	payload: payload
    });
    
    export const fulfilledTopAnime = payload => ({
    	type: types.TOPANIME_SUCCESS,
    	payload: payload
    });
    
    export const failedTopAnime = payload => ({
    	type: types.TOPANIME_FAILURE,
    	payload: payload
    });

    This file contains our action creators that returns plain JavaScript objects.

    Reducer.js

    import { combineReducers } from "redux";
    
    import * as types from "./types";
    
    export const initialState = {};
    
    const searchResults = (state = [], { type, payload }) => {
    	switch (type) {
    		case types.SEARCH_SUCCESS:
    			return [...payload];
    		case types.SEARCH_FAILURE:
    			return state;
    		default:
    			return state;
    	}
    };
    
    const topAnimes = (state = [], { type, payload }) => {
    	switch (type) {
    		case types.TOPANIME_SUCCESS:
    			return [...payload];
    		case types.TOPANIME_FAILURE:
    			return state;
    
    		default:
    			return state;
    	}
    };
    
    // State Selectors
    export const getSearchResults = state => state.searchResults;
    export const getTopAnimesResults = state => state.topAnimes;
    
    export const animeReducer = combineReducers({
    	searchResults,
    	topAnimes
    });

    The reducer.js file contains two reducer:

    • `searchResults`: This is where the state of the search results is managed
    • `loadingSearchResults`: This is used to manage the loading state of the top airing animes.

    Api.js

    import axios from "axios";
    import { baseURL } from "./constants";
    
    export async function fetchTopAnimes() {
    	return axios.get(`${baseURL}/top/anime/1/airing`);
    }
    
    export async function fetchAllAnimes(query) {
    	if (query) {
    		return axios.get(`${baseURL}/search/anime/?q=${query}&page=1`);
    	} else {
    		return axios.get(`${baseURL}/search/anime/?order_by=score&page=1`);
    	}
    }

    The file contains two functions that return promises.

    • `fetchTopAnimes`:  This function makes an API call to get the top airing animes and then returns a promise.
    • `fetchAllAnimes`:  This function makes an API call to get the results of the search query if there is a query, or it gets the best animes of all time if there is no query string. It also returns a promise.

    saga.js

    import { call, put, takeEvery, all } from "redux-saga/effects";
    import { fetchTopAnimes, fetchAllAnimes } from "../Api";
    import { SEARCH_REQUEST, TOPANIME_REQUEST } from "./types";
    import {
    	fulfilledTopAnime,
    	failedTopAnime,
    	fulfilledSearchAnime,
    	failedSearchAnime
    } from "./actions";
    
    function* getTopAnimesWorker(action) {
    	try {
    		const data = yield call(fetchTopAnimes);
    		let res = data.data.top;
    		yield put(fulfilledTopAnime(res));
    	} catch (err) {
    		yield put(failedTopAnime(err));
    	}
    }
    function* getSearchAnimesWorker(action) {
    	try {
    		const data = yield call(fetchAllAnimes, action.payload);
    		let res = data.data.results;
    		yield put(fulfilledSearchAnime(res));
    	} catch (err) {
    		yield put(failedSearchAnime(err));
    	}
    }
    
    function* getTopAnimeWatcher() {
    	yield takeEvery(TOPANIME_REQUEST, getTopAnimesWorker);
    }
    
    function* getSearchAnimesWatcher() {
    	yield takeEvery(SEARCH_REQUEST, getSearchAnimesWorker);
    }
    
    export default function* rootSaga() {
    	yield all([getTopAnimeWatcher(), getSearchAnimesWatcher()]);
    }

    This is the file where all the async calls/side-effects are being handled. In redux-thunk the async logic is put in the action creators, but in redux-saga, we have a dedicated file for this usually called sagas.

    The saga file is usually structured in a way that we have two types of generator functions(sagas):

    • Worker Function
    • Watcher Function

    The Watcher function waits/watches for a specific action to be dispatched to the redux store, then it calls the respective worker function which handles the side-effects/API calls

    The two watcher functions are:

    • getTopAnimeWatcher
    • getSearchAnimesWatcher

    The `getTopAnimeWatcher` yields an effect called `takeEvery()`, which takes an action and a function as arguments. `takeEvery` is a redux-saga helper effect that tells redux-saga to continuously and concurrently wait for an action of type `TOPANIME_REQUEST` to be dispatched, immediately it is dispatched, it should execute the `getTopAnimesWorker` function which handles the side-effects. We have another similar helper effects to `takeEvery` that can be used to listen for actions dispatched called `takeLatest`.

    `takeLatest` calls its worker saga every time an action’s dispatched and it automatically cancels any previous execution of the worker saga if it is still running, while `takeEvery` does not cancel any previous saga.

    The `getSearchAnimesWatcher` is similar to the `getTopAnimeWatcher`. When an action of type `SEARCH_REQUEST` is dispatched, it calls the `getSearchAnimesWorker` function.

    We now know that the watcher functions call the worker functions, so what happens in them?

    In the `getTopAnimesWorker` function, it first yields a function `call` that takes the `fetchTopAnimes` function we exported from the `Api.js` file.

    `call` is another helper effects provided by redux-saga, it is used to execute/call a function but if that function is a promise it pauses the saga until the promises are resolved. The `call` effect is like `await` in async-await syntax.

    const data = yield call(fetchTopAnimes);

    So what the line above does is call the `fetchTopAnimes` async function, wait for it to be resolved, then the response is saved in the `data` variable. if the promise failed then it is caught in the catch block of the `try-catch`.

    if the promise was successful execution of the saga resumes to the next line:

    yield put(fulfilledTopAnime(res));

    `put` is another helper effect which is used to dispatch an action to the redux store. The line above dispatches a `fulfilledTopAnime()` action with the response as an argument, so the reducer can update the store state.

    If the promise failed then execution continues in the catch block

    catch(e){
       yield put(failedTopAnime(err));
    }

    This dispatches an action to the store to indicate the request failed.

    `getSearchAnimesWorker` is similar to the `getTopAnimesWorker` function, the only difference is that the `call` effect takes a second argument.

    const data = yield call(fetchAllAnimes, action.payload);

    This second argument makes it possible to pass an argument to the `fetchAllAnimes` function, so it looks something like this when it is called

    call(fetchAllAnimes(action.payload));

    Apart from that, everything else is the same as the `getTopAnimesWorker` we talked about earlier.

    Finally, there is one more function in the saga file we have not discussed yet; the rootSaga generator function. This function uses another helper effect `all`. This effect tells redux-saga to run the functions in parallel.

    The rootSaga function runs the two watcher sagas in parallel, so it can be exported and ran by the saga middleware. Basically, it connects the sagas to the redux-saga middleware

    sagaMiddleware.run(rootSaga);

    Above is a line of code in the `store.js` file that runs the saga.

    This is just a trivial example to show you how to use redux-saga, but it is obvious there are benefits of using it instead of redux-thunk.

    Some benefits of using Redux-saga:

    • Easier to test because we don’t have to mock API calls
    • Looks cleaner because we don’t have to deal with callbacks and asynchronous tasks are achieved in a synchronous nature.

    Conclusion

    Redux-saga might be an overkill for the trivial example, but it thrives when you need to handle complex asynchronous tasks in Redux. Personally, I use redux-saga for most of my Redux-based projects, because it looks a lot cleaner and easier to understand than the promise-based redux-thunk.

    Github: https://github.com/nero2009/Anime-viewer

    Here is an illustration of the flow:

    Flow with sagas
    Flow with sagas

    References

    • Understanding Generators in ES6 JavaScript with Examples
    • Redux Saga documentation
    • Why do we need middleware for async flow in Redux?
    generator function JavaScript react redux redux flow redux store redux-saga redux-thunk web-development
    Share. Facebook Twitter Pinterest LinkedIn Tumblr Email
    Adaware Oghenero

      Related Posts

      Streamlining Resource Allocation for Enhanced Project Success

      December 18, 2024

      Conducting Effective Post-Project Evaluations: A Guide

      December 16, 2024

      Strategies for Keeping Projects on Track and Meeting Deadlines

      December 10, 2024
      Leave A Reply Cancel Reply

      You must be logged in to post a comment.

      Stay In Touch
      • Facebook
      • Twitter
      • Pinterest
      • Instagram
      • YouTube
      • Vimeo
      Don't Miss
      Startups December 18, 2024

      Leveraging Crowdfunding to Successfully Fund Your Startup

      Crowdfunding has emerged as a powerful tool for startups, allowing entrepreneurs to validate ideas and secure funding. By engaging potential customers early, leveraging social media, and crafting compelling narratives, businesses can effectively harness this funding model for success.

      The Best Work Tools for Remote Teams — Part 2: Team Communication

      May 3, 2019

      The Impact of Integrated Development Environments on Coding

      December 16, 2024

      Strategic LinkedIn Techniques for Real Estate Lead Generation

      December 16, 2024

      Categories

      • AI & Automation
      • Angular
      • ASP.NET
      • AWS
      • B2B Leads
      • Beginners
      • Blogs
      • Business Growth
      • Case Studies
      • Comics
      • Consultation
      • Content & Leadership
      • CSS
      • Development
      • Django
      • E-commerce & Retail
      • Entrepreneurs
      • Entrepreneurship
      • Events
      • Express.js
      • Facebook Ads
      • Finance & Fintech
      • Flask
      • Flutter
      • Franchising
      • Funnel Strategy
      • Git
      • GraphQL
      • Home Services Marketing
      • Influencer & Community
      • Interview
      • Java
      • Java Spring
      • JavaScript
      • Job
      • Laravel
      • Lead Generation
      • Legal & Compliance
      • LinkedIn
      • Machine Learning
      • Marketing Trends
      • Medical Marketing
      • MSP Lead Generation
      • MSP Marketing
      • NestJS
      • Next.js
      • Node.js
      • Node.js Lessons
      • Paid Advertising
      • PHP
      • Podcasts
      • POS Tutorial
      • Programming
      • Programming
      • Python
      • React
      • React Lessons
      • React Native
      • React Native Lessons
      • Recruitment
      • Remote Job
      • SaaS & Tech
      • SEO & Analytics
      • Soshace
      • Startups
      • Swarm Intelligence
      • Tips
      • Trends
      • Vue
      • Wiki
      • WordPress
      Top Posts

      Advanced Mapmaking: Using d3, d3-scale and d3-zoom With Changing Data to Create Sophisticated Maps

      JavaScript March 11, 2020

      Understanding The GIT Workflow

      Git January 27, 2020

      Leveraging LinkedIn Prospecting for Local Business Expansion

      LinkedIn November 26, 2024

      RxJS Introduction

      Programming February 14, 2017

      Subscribe to Updates

      Get The Latest News, Updates, And Amazing Offers

      About Us
      About Us

      Soshace Digital delivers comprehensive web design and development solutions tailored to your business objectives. Your website will be meticulously designed and developed by our team of seasoned professionals, who combine creative expertise with technical excellence to transform your vision into a high-impact, user-centric digital experience that elevates your brand and drives measurable results.

      7901 4th St N, Suite 28690
      Saint Petersburg, FL 33702-4305
      Phone: 1(877)SOSHACE

      Facebook X (Twitter) Instagram Pinterest YouTube LinkedIn
      Our Picks
      ASP.NET

      Fluent Validation in ASP.NET MVC

      Interview

      Conducting a Better Technical Interview: Problems and Solutions

      JavaScript

      JSX vs HTML: Overview + Answers to FAQs

      Most Popular

      Node.js Lesson 14: Asynchronous Development

      JavaScript

      Strategic Approaches to Securing Startup Funding Successfully

      Startups

      Guide to HR adviser and Clients lessening

      Franchising
      © 2025 Soshace Digital.
      • Home
      • About
      • Services
      • Contact Us
      • Privacy Policy
      • Terms & Conditions

      Type above and press Enter to search. Press Esc to cancel.