Handling asynchronous actions with Redux Thunk
Last Updated :
10 Jun, 2024
Managing asynchronous actions using Redux Thunk is a prevalent approach in Redux-based applications. Redux Thunk serves as middleware, enabling the creation of action creators that return functions rather than action objects. These functions can execute asynchronous tasks, like fetching data from an API, prior to dispatching actions to modify the Redux store.
We generally assume that Redux reducers must not contain "side effects". A "side effect" is any change to state or behaviour that can be seen outside of returning a value from a function.
Common examples of side effects are:
- Logging data to the console
- Writing to a file
- Initiating an asynchronous timer
- Sending AJAX HTTP requests
Despite these restrictions, practical applications inevitably require such functionalities at some point. In such case we can use middleware.
Steps for creating an application
Step 1: Create a new React project using Create React App or any other method you prefer.
npx create-react-app userfetchpro
Step 2: Install Redux ,React-Redux and redux-thunk packages using npm or yarn.
npm install redux react-redux redux-thunk
or
yarn add redux react-redux redux-thunk
Below is a concise project structure for a counter application developed using Redux:
Project Structure
gfgUpdated dependencies in package.json file:
"dependencies": {
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-redux": "^9.1.2",
"react-scripts": "5.0.1",
"redux": "^5.0.1",
"redux-thunk": "^3.1.0",
"web-vitals": "^2.1.4"
},
Approach
- Set up Redux store with Redux Thunk middleware:
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
// Assuming you have a rootReducer
import rootReducer from './reducers';
const store = createStore(
rootReducer,
applyMiddleware(thunk)
);
- Write action creators that return functions:
const fetchData = () => {
return async (dispatch) => {
dispatch({ type: 'FETCH_DATA_REQUEST' });
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
dispatch({ type: 'FETCH_DATA_SUCCESS', payload: data });
} catch (error) {
dispatch({ type: 'FETCH_DATA_FAILURE', payload: error.message });
}
};
};
- Dispatch the action creator from your components:
import { useDispatch } from 'react-redux';
import { fetchData } from './actions';
const MyComponent = () => {
const dispatch = useDispatch();
useEffect(() => {
dispatch(fetchData());
}, [dispatch]);
};
- This setup allows you to handle asynchronous actions in Redux easily. The action creator fetchData returns a function that receives dispatch as an argument. Inside this function, you can perform asynchronous operations and dispatch regular synchronous actions to update the Redux store based on the result of the asynchronous operation.
Example: Below is an example of How to mock the Redux store for testing purposes.
JavaScript
import React from 'react';
import { Provider } from 'react-redux';
import store from './configureStore';
import UserList from './UserList';
const App = () => {
return (
<Provider store={store}>
<div>
<h1>User Fetch Pro</h1>
<UserList />
</div>
</Provider>
);
};
export default App;
JavaScript
import { createStore, applyMiddleware } from 'redux';
import {thunk} from 'redux-thunk';
import rootReducer from './userReducer';
const store = createStore(rootReducer, applyMiddleware(thunk));
export default store;
JavaScript
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
JavaScript
async function getUsers() {
return fetch("https://jsonplaceholder.typicode.com/users")
.then((response) => response.json())
.then((json) => {
return json;
})
.catch((error) => {
throw error;
});
}
export default getUsers;
JavaScript
import getUsers from "./service";
export const FETCH_USERS_REQUEST = "FETCH_USERS_REQUEST";
export const FETCH_USERS_SUCCESS = "FETCH_USERS_SUCCESS";
export const FETCH_USERS_FAILURE = "FETCH_USERS_FAILURE";
export const fetchUsers = () => {
return async (dispatch) => {
dispatch({ type: FETCH_USERS_REQUEST });
try {
getUsers().then((res) => {
dispatch({ type: FETCH_USERS_SUCCESS, payload: res });
});
} catch (error) {
dispatch({ type: FETCH_USERS_FAILURE, payload: error.message });
}
};
};
JavaScript
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { fetchUsers } from './userActions';
const UserList = () => {
const dispatch = useDispatch();
const { users, loading, error } = useSelector(state => state);
useEffect(() => {
dispatch(fetchUsers());
}, [dispatch]);
if (loading) {
return <div>Loading...</div>;
}
if (error) {
return <div>Error: {error}</div>;
}
return (
<div>
<h2>User List</h2>
<ul>
{users && users.length>0 && users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
</div>
);
};
export default UserList;
JavaScript
import { FETCH_USERS_REQUEST, FETCH_USERS_SUCCESS, FETCH_USERS_FAILURE } from './userActions';
const initialState = {
users: [],
loading: false,
error: null
};
const userReducer = (state = initialState, action) => {
switch (action.type) {
case FETCH_USERS_REQUEST:
return { ...state, loading: true, error: null };
case FETCH_USERS_SUCCESS:
return { ...state, loading: false, users: action.payload, error: null };
case FETCH_USERS_FAILURE:
return { ...state, loading: false, error: action.payload };
default:
return state;
}
};
export default userReducer;
Command to Run the project:
npm start
or
yarn start
Output:
gfg
Similar Reads
How to dispatch asynchronous actions using Redux Thunk?
Asynchronous actions are very important in web development, particularly in tasks such as fetching data from API. Redux Thunk is a middleware using which you can write action creators that return a function instead of an object. This function can perform asynchronous operations and dispatch actions
3 min read
How to Handle Forms in Redux Applications?
Handling forms in Redux applications involves managing form data in the Redux store and synchronizing it with the UI. By centralizing the form state in the Redux store, you can easily manage form data, handle form submissions, and maintain consistency across components. We will discuss a different a
5 min read
How to handle asynchronous operations in Node ?
NodeJS, renowned for its asynchronous and event-driven architecture, offers powerful mechanisms for handling asynchronous operations efficiently. Understanding how to manage asynchronous operations is crucial for NodeJS developers to build responsive and scalable applications. What are Asynchronous
2 min read
How to handle server-side errors in Redux applications ?
It is essential to deal with server-side errors while building reliable Redux applications. This ensures a seamless user experience, even if problems occur during server requests. This guide will explain the effective management of server errors in the Redux architecture through Redux Thunk middlewa
3 min read
How to Handle Errors in React Redux applications?
To handle errors in Redux applications, use try-catch blocks in your asynchronous action creators to catch errors from API calls or other async operations. Dispatch actions to update the Redux state with error information, which can then be displayed to the user in the UI using components like error
4 min read
What are Action's creators in React Redux?
In React Redux, action creators are functions that create and return action objects. An action object is a plain JavaScript object that describes a change that should be made to the application's state. Action creators help organize and centralize the logic for creating these action objects.Action C
4 min read
How to Normalize State in Redux Applications ?
In Redux applications, efficient state management is essential for scalability and maintainability. Normalization is a technique used to restructure complex state data into a more organized format, improving performance and simplifying state manipulation. This article covers the concept of normaliza
3 min read
How to handle data fetching in React-Redux Applications ?
Data fetching in React-Redux applications is a common requirement to retrieve data from APIs or other sources and use it within your components. This article explores various approaches to handling data fetching in React-Redux applications, providing examples and explanations for each approach.Table
4 min read
Explain Actionâs in Redux
In this article, we are going to learn about Action in Redux. Actions are plain JavaScript object that contains information. Action is one of the building blocks of Redux. Redux is a state managing library used in JavaScript apps. It is used to manage the data and the state of the application. Uses
5 min read
How to test React-Redux applications?
Testing React-Redux applications is crucial to ensure their functionality, reliability, and maintainability. As we know, the React-Redux application involves complex interactions between components and Redux state management, testing helps us to identify and prevent bugs, regressions, and performanc
10 min read