Open In App

How to dispatch asynchronous actions using Redux Thunk?

Last Updated : 29 Feb, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

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 to try and catch blocks.

What is Redux Thunk?

Redux Thunk is like a co-worker for Redux, giving it the power to handle asynchronous actions. It’s that extra tool that allows your Redux store to deal with things like fetching data from a server or performing tasks that take some time. With Redux Thunk, your app can smoothly manage both synchronous and asynchronous operations.

Syntax of Redux Thunk:

export const fetchData = createAsyncThunk(
'data/fetchData',
async () => { } // runs when fetchData is dispatched
);

Approach to dispatch asynchronous actions using Redux Thunk

The approach is very simple. We will use the `createAsyncThunk` function provided by Redux Toolkit to create asynchronous action creators. This function will wrap an asynchronous function that will run when the parent function is dispatched.

Steps to Create React App and Installing Required Modules

Step 1: Create a new React JS app and enter into the directory by running the following commands

npx create-react-app my-app
cd my-app

Step 2: Install the required modules

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

Project Structure:

1

Dependencies: The updated package.json file should look like this.

"dependencies": {
"@reduxjs/toolkit": "^2.2.1",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-redux": "^9.1.0",
"react-scripts": "5.0.1",
"redux-thunk": "^3.1.0",
"web-vitals": "^2.1.4"
}

Example: Here is an working example of the approach. We have created and updated the following files.

CSS




/* App.css */
 
.container {
    max-width: 600px;
    margin: 0 auto;
    padding: 20px;
}
 
.fetch-button {
    padding: 10px 20px;
    margin-bottom: 20px;
    font-size: 16px;
    background-color: #007bff;
    color: #fff;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    transition: background-color 0.3s;
}
 
.fetch-button:hover {
    background-color: #0056b3;
}
 
.loading {
    margin-top: 20px;
    font-size: 60px;
}
 
.todos-list {
    list-style: none;
    padding: 0;
}
 
.todos-list li {
    margin-bottom: 10px;
    padding: 10px;
    border: 1px solid #ddd;
    border-radius: 5px;
}


Javascript




//index.js
 
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { Provider } from 'react-redux';
import store from './redux/store';
 
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <Provider store={store}>
        <App />
    </Provider>
);


Javascript




// App.js
 
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { fetchTodos } from './redux/userSlice';
import './App.css';
 
function App() {
  const dispatch = useDispatch();
  const todos = useSelector((state) => state.todos);
 
  return (
    <div className="container">
      <h1>Todos</h1>
      <button className="fetch-button" onClick={
        () => dispatch(fetchTodos())
        }>
          Fetch Todos</button>
      {todos.loading && <p className="loading">Loading...</p>}
      <ul className="todos-list">
        {todos.data?.map((todo) => (
          <li key={todo.id}>{todo.title}</li>
        ))}
      </ul>
    </div>
  );
}
 
export default App;


Javascript




// userSlice.js
 
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
 
export const fetchTodos = createAsyncThunk(
    'todos/fetchTodos',
    async () => {
        try {
            const response = await
                fetch('https://jsonplaceholder.typicode.com/todos');
            if (!response.ok) {
                throw new Error('Failed to fetch todos');
            }
            const todos = await response.json();
            return todos;
        } catch (error) {
            throw new Error('Error fetching todos');
        }
    }
);
 
const todosSlice = createSlice({
    name: 'todos',
    initialState: {
        data: [],
        loading: false,
        error: null,
    },
    reducers: {},
    extraReducers: (builder) => {
        builder
            .addCase(fetchTodos.pending, (state) => {
                state.loading = true;
                state.error = null;
            })
            .addCase(fetchTodos.fulfilled, (state, action) => {
                state.loading = false;
                state.data = action.payload;
            })
            .addCase(fetchTodos.rejected, (state, action) => {
                state.loading = false;
                state.error = action.error.message;
            });
    },
});
 
export default todosSlice.reducer;


Javascript




// store.js
 
import { configureStore } from '@reduxjs/toolkit';
import todosReducer from './userSlice';
 
const store = configureStore({
    reducer: {
        todos: todosReducer,
    },
});
 
export default store;


Output: Run the server by running the following command

npm start
2024-02-2103-21-32-ezgifcom-video-to-gif-converter

output



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads