Engineering

Elevate Your React Projects with Redux Saga and Toolkit Integration

-By Priya Nair

Are you struggling with messy code in your web projects? Redux Saga and Redux Toolkit are your essential tools for web development.

Redux Saga is middleware that manages side effects, such as async tasks and data fetching, in Redux. It uses ES6 Generators to enhance asynchronous coding, making it more readable and testable. By compartmentalizing asynchronous operations within distinct saga functions, it ensures a tidy codebase and improved maintainability.

Redux Toolkit is an official Redux package that simplifies store setup, reducer creation, and action handling. Emphasizing best practices, it reduces boilerplate and streamlines state management for efficiency and intuitiveness.

Combining these tools creates an organized, less error-prone coding environment, perfectly poised for scalability. Embrace them and transform how you perceive and manage state and asynchronous actions in your projects.

Why choose Redux Saga?

Getting Started with Redux Saga and Redux Toolkit: A Practical Guide

Let’s start by initiating a new React project, and then weave in Redux Saga and Redux Toolkit.

Step1: Initiate a React Project

Fire up a new React project with this command:

npx create-react-app redux-saga-project

Step2: Add Necessary Libraries

Move to the project's directory and bring in the essential libraries:

npm install react-redux @reduxjs/toolkit redux-saga

Step3: Structure Your Project

Forge a redux directory at the project's base. It's the sanctuary for all Redux-centric code. Within redux, spawn two offspring folders: saga (for saga-related code) and features (for reducer slices).

In the features Folder:

Create a reducer slice for managing user data state in a file named userSlice.js:

import { createSlice } from'@reduxjs/toolkit';

 

const initialState = {

 user:{

   id:'',

  username: '',

 },

 error:'',

};

 

export const userSlice = createSlice({

 name: 'userData',

initialState,

reducers: {

  fetchDataSuccess: (state, action) => {

    state.user = action.payload;

   },

  fetchDataError: (state, action) => {

    state.error = action.payload;

   },

  resetTemporaryState: (state) => {

    return initialState; // Return a new state object instead of modifyingthe existing one

   },

 },

});

 

export const { fetchDataSuccess,fetchDataError, resetTemporaryState } = userSlice.actions;

 

export const userDataSelector = (state) =>state.userData.user;

 

export default userSlice.reducer;

 

 

The slice needs parameters like name,initialState and list of reducers. Here the reducers we are using is forsuccessful fetch, data error and to reset state.

In the saga Folder:

Create a saga for fetching user data in a file named userSaga.js:

The main concept used in Redux Saga is Generators, fetch UserData is a generator function to fetch api calls. 


 

 

import { take Latest, call, put } from 'redux-saga/effects';

import { GET_USERS, fetchDataError, fetchDataSuccess } from '../features/userSlice';

 

function* fetchUserData(val) {

 try {

  const id = val.payload.id;

  const response = yield call(fetch, `https://dummyjson.com/users/${id}`);

  const data = yield response.json();

  yield put(fetchDataSuccess({ id: data.id, username: data.firstName }));

 }catch (error) {

  yield put(fetchDataError(error));

 }

}

 

export function* watchUserData() {

 yield takeLatest(GET_USERS, fetchUserData);

//fetchUserData is called when user dispatches an action “GET_USERS”

}

 

In this code the fetch api iscalled and response of api call is stored in the user state , similar case forerror.

Configure Redux Store in index.js:

Inside the redux folder we’ll create a index.jsfile. This is just a boilerplate code that we need to configure once and herewe are gonna pass reducers and slices we made

 

import createSagaMiddleware from"@redux-saga/core";

import { configureStore } from"@reduxjs/toolkit";

import { all } from 'redux-saga/effects';

import { watchUserData } from"./sagas/userSaga";

import userReducer from"./features/userSlice";

 

function* rootSaga() {

 yieldall([watchUserData()]);

}

 

const sagaMiddleware = createSagaMiddleware();

 

const store = configureStore({

reducer: {

  userData: userReducer,

 },

middleware: [sagaMiddleware],

});

 

sagaMiddleware.run(rootSaga);

 

export default store;

Connect to the Application:

Wrap your app with the Redux Providercomponent in the index.js file:

 

import React from 'react';

import ReactDOM from 'react-dom';

import { Provider } from 'react-redux';

import store from './redux/index';

import App from './App';

import './index.css';

 

ReactDOM.render(

<Provider store={store}>

  <React.StrictMode>

    <App />

  </React.StrictMode>

</Provider>,

document.getElementById('root')

);

Final Steps - Using Redux Saga and Redux Toolkit:

In your App.js file, connect the component toRedux and utilize the actions and state:

 

import React from 'react';

import { useDispatch, useSelector } from'react-redux';

import { GET_USERS, resetTemporaryState } from'./redux/features/userSlice';

 

function App() {

 constdispatch = useDispatch();

 constuserState = useSelector((state) => state.userData.user);

// To access the state data weneed to use the hook useSelector, userData is exported from the userslice

 

 

 constcallApi = () => {

// dispatch the type correspondingto the generator function you need to call, along with the payload you want tosend. Payload is optional

  dispatch({

    type: GET_USERS,

    payload: { id: 1 },

   });

 };

 

 constclearData = () => {

  dispatch(resetTemporaryState()); // This is how you call the reducersdirectly

  // dispatch(fetchDataSuccess({id:2,name:"Priya"})) // This isjust an example on how to save the data in state

 

 };

 

 return(

  <div className="App">

    <button onClick={callApi}>Fetch</button>

    <button onClick={clearData}>Clear</button>

    <pre>{JSON.stringify(userState, null, 2)}</pre>

  </div>

 );

}

 

export default App;

 

Setting up Redux Saga with Redux Toolkit in a React app? This guide breaks it down. Learn to create reducer slices, define sagas, configure the Redux store, and link components using useSelector and useDispatch hooks.

While this provides a foundational understanding, real-world applications may involve more advanced scenarios and error handling. Use this tutorial to master the asynchronous actions and state management capabilities of Redux Saga and Redux Toolkit.

Conclusion

Making the decision to integrate Redux Saga into your toolkit requires careful consideration. This powerful middleware excels at managing intricate asynchronous workflows and coordinating multiple actions, offering built-in methods for cancellation, debouncing, and error handling. However, it also presents challenges, such as a steep learning curve and increased code complexity. While Redux Saga is invaluable for complex scenarios, other Redux middleware or hooks might be more appropriate for simpler projects. Ultimately, the specific needs of your application should guide your decision. A thorough examination of Redux Saga's strengths and limitations is crucial for making a choice that will enhance your Redux application's maintainability and efficiency. Choose wisely with Codvo, and watch your application thrive!

You may also like