How to Implement Redux Thunk in React
This article provides a step-by-step guide on how to integrate and use Redux Thunk in a React application. You will learn how to install the necessary dependencies, configure the Redux store with the thunk middleware, write asynchronous action creators to fetch external data, and connect those actions to your React components.
Step 1: Install Dependencies
To get started, you need to install Redux, React-Redux, and Redux Thunk. Run the following command in your terminal:
npm install redux react-redux redux-thunk(Note: If you are using Redux Toolkit, Redux Thunk is already built-in, but this guide focuses on the standard implementation to show how the middleware works).
Step 2: Configure the Redux Store with Thunk
To use Redux Thunk, you must apply it as middleware when creating
your Redux store. Create a file named store.js and add the
following configuration:
import { createStore, applyMiddleware } from 'redux';
import { thunk } from 'redux-thunk';
import rootReducer from './reducer';
const store = createStore(
rootReducer,
applyMiddleware(thunk)
);
export default store;Step 3: Create a Reducer
Create a reducer file (reducer.js) to handle the state
changes based on the API request lifecycle (loading, success, and
failure).
const initialState = {
loading: false,
data: [],
error: ''
};
const dataReducer = (state = initialState, action) => {
switch (action.type) {
case 'FETCH_DATA_REQUEST':
return { ...state, loading: true };
case 'FETCH_DATA_SUCCESS':
return { loading: false, data: action.payload, error: '' };
case 'FETCH_DATA_FAILURE':
return { loading: false, data: [], error: action.payload };
default:
return state;
}
};
export default dataReducer;Step 4: Write the Asynchronous Action Creator (The Thunk)
A “thunk” is a function that returns another function. The inner
function receives the Redux dispatch and
getState methods as arguments. This allows you to perform
side effects, like API calls, and dispatch synchronous actions once the
asynchronous operations complete.
Create an action file named actions.js:
export const fetchDataRequest = () => ({
type: 'FETCH_DATA_REQUEST'
});
export const fetchDataSuccess = (data) => ({
type: 'FETCH_DATA_SUCCESS',
payload: data
});
export const fetchDataFailure = (error) => ({
type: 'FETCH_DATA_FAILURE',
payload: error
});
// The Thunk Action Creator
export const fetchUsers = () => {
return (dispatch) => {
dispatch(fetchDataRequest());
fetch('https://jsonplaceholder.typicode.com/users')
.then((response) => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then((data) => {
dispatch(fetchDataSuccess(data));
})
.catch((error) => {
dispatch(fetchDataFailure(error.message));
});
};
};Step 5: Provide the Store to React
Wrap your root React component with the Provider
component from react-redux and pass the store as a
prop.
import React from 'react';
import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux';
import store from './store';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={store}>
<App />
</Provider>
);Step 6: Dispatch the Thunk in Your Component
Now, you can use React-Redux hooks (useDispatch and
useSelector) to dispatch the asynchronous thunk action and
read the state inside your functional components.
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { fetchUsers } from './actions';
function App() {
const dispatch = useDispatch();
const { data, loading, error } = useSelector((state) => state);
useEffect(() => {
dispatch(fetchUsers());
}, [dispatch]);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error}</p>;
return (
<div>
<h1>Users List</h1>
<ul>
{data.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
</div>
);
}
export default App;