Home >Web Front-end >JS Tutorial >How to make a Redux Saga flow for API calls?
Use Redux Saga to simplify API workflow in React/React Native projects
This article is not an expert guide, but it will try to explain how to leverage Redux Saga to handle side effects in your React or React Native projects. If your application involves a lot of API calls, Redux Saga can simplify the process and make the code more manageable.
Why choose Redux Saga?
Redux Saga is a middleware that manages side effects (such as API calls) in a clear and predictable way. Instead of stuffing API logic in components or reducers, you can delegate these tasks to saga. Saga allows you to write asynchronous code that looks synchronous, using special JavaScript functions called generators.
Set folder structure
Before delving into saga, be sure to structure your project so it can scale. Here's the basic structure I follow:
The Services folder contains reusable API call functions. Here's an example of the "Change Password" API:
<code class="language-javascript">// ChangePasswordService.js import {Constants} from '../../Config'; import Ajax from './base'; const BASE_URL = Constants.IS_DEVELOPING_MODE ? Constants.BASE_URL.DEV : Constants.BASE_URL.PROD; export default { ChangePassword: async params => { return fetch(`${BASE_URL}api/change-password`, { method: 'POST', body: params, headers: { Accept: 'multipart/form-data', }, }) .then(response => Ajax.handleResponse(response)) .then(data => { console.log('Data', data); return data; }); }, };</code>
Here, we define a ChangePassword function to make API calls. It uses fetch to send a POST request to the endpoint and a helper function (Ajax.handleResponse) to handle the response.
Reducers listen for dispatched actions and update status accordingly. Here is a reducer for managing password changes:
<code class="language-javascript">// PasswordChangeSlice.js import {createSlice} from '@reduxjs/toolkit'; const passwordChangeSlice = createSlice({ name: 'passwordChange', initialState: { data: null, isChangeSuccess: null, error: null, message: null, }, reducers: { changePassword: state => { state.isChangeSuccess = null; state.error = null; state.message = ''; }, changePasswordSuccess: (state, action) => { state.data = action.payload; state.message = 'Password changed successfully'; state.isChangeSuccess = true; }, changePasswordFail: (state, action) => { state.error = action.payload; state.message = 'Something went wrong'; state.isChangeSuccess = false; }, }, }); export const {changePassword, changePasswordSuccess, changePasswordFail} = passwordChangeSlice.actions; export default passwordChangeSlice.reducer;</code>
This reducer has three actions:
changePassword
: Reset state when request starts. changePasswordSuccess
: Update status with success data. changePasswordFail
: Update status with error information. Now to the point! The Saga handles the actual API calls and dispatches actions based on the responses. Here is a saga for the "Change Password" API:
<code class="language-javascript">import {all, call, put, takeEvery} from 'redux-saga/effects'; import API from '../Services/ChangePasswordService'; import { changePasswordFail, changePasswordSuccess, } from '../Reducers/PasswordChangeSlice'; function* changePasswordSaga({payload}) { try { const response = yield call(API.ChangePassword, payload); if (response?.data) { yield put(changePasswordSuccess(response.data)); } else if (response?.errors) { yield put(changePasswordFail(response.errors)); } } catch (error) { yield put(changePasswordFail(error.message)); } } function* passwordSaga() { yield all([ takeEvery('passwordChange/changePassword', changePasswordSaga), ]); } export default passwordSaga;</code>
call
: Call the API function (API.ChangePassword) and wait for the result. put
: dispatch actions to update status. takeEvery
: Listen to a specific action (changePassword
) and trigger the corresponding worker saga (changePasswordSaga
). If the API call succeeds, the saga will emit changePasswordSuccess
; if it fails, changePasswordFail
will be emitted.
To trigger the process, we create a custom hook to dispatch the changePassword
action:
<code class="language-javascript">// useChangePasswordActions.js import {useDispatch, useSelector} from 'react-redux'; import {changePassword} from '../Reducers/PasswordChangeSlice'; export const useChangePasswordActions = () => { const dispatch = useDispatch(); const passwordState = useSelector(state => state?.changePassword); const changePasswordCall = params => { dispatch(changePassword(params)); }; return { passwordState, changePasswordCall, }; };</code>
How it works
changePasswordCall
in the custom hook. changePassword
action updates the status to indicate that the request is in progress. changePassword
and triggers worker saga. Summary
This setup organizes your API workflow into clear and manageable steps:
Remember, this is just one way to organize your project. If you have more experience or ideas, please feel free to comment with your strategies. I will cover more about saga in future articles as I learn and improve.
Happy programming! ?
The above is the detailed content of How to make a Redux Saga flow for API calls?. For more information, please follow other related articles on the PHP Chinese website!