WHAT is Redux Thunk?
Redux Thunk is a middleware that allows you to write functions (not just plain objects) as actions.
Normally Redux ONLY accepts:
{ type: "INCREMENT" } // plain object
But with Thunk, you can dispatch functions like:
(dispatch) => {
// async code
}
π₯ Without Thunk (what happens?)
If you try:
dispatch(fetchUsers());
Redux expects fetchUsers() to return an object like:
{ type: "FETCH_USERS" }
But Thunk returns a function:
(dispatch) => { ... }
Redux will say: β βI donβt understand functions.β
Redux Thunk tells Redux:
π βIf the action is a function, call it and pass dispatch as argument.β
This is how async API calls become possible in Redux.
β 1. Install Redux Toolkit + Thunk
(Thunk comes built-in with Redux Toolkit)
npm install @reduxjs/toolkit react-redux
β 2. Create a Slice + Thunk
features/users/userSlice.js
import { createSlice } from "@reduxjs/toolkit";
// ----- Thunk (async action creator) -----
export const fetchUsers = () => {
return async (dispatch) => {
dispatch(fetchStart());
try {
const res = await fetch("https://jsonplaceholder.typicode.com/users");
const data = await res.json();
dispatch(fetchSuccess(data));
} catch (err) {
dispatch(fetchFail(err.message));
}
};
};
const userSlice = createSlice({
name: "users",
initialState: {
loading: false,
data: [],
error: null,
},
reducers: {
fetchStart(state) {
state.loading = true;
state.error = null;
},
fetchSuccess(state, action) {
state.loading = false;
state.data = action.payload;
},
fetchFail(state, action) {
state.loading = false;
state.error = action.payload;
},
},
});
export const { fetchStart, fetchSuccess, fetchFail } = userSlice.actions;
export default userSlice.reducer;
β 3. Add reducer to the store
store.js
import { configureStore } from "@reduxjs/toolkit";
import userReducer from "./features/users/userSlice";
const store = configureStore({
reducer: {
users: userReducer,
},
});
export default store;
β 4. Use Thunk in a Component
App.js
import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { fetchUsers } from "./features/users/userSlice";
export default function App() {
const dispatch = useDispatch();
const { loading, data, error } = useSelector((state) => state.users);
useEffect(() => {
dispatch(fetchUsers());
}, [dispatch]);
return (
<div>
<h2>Users</h2>
{loading && <p>Loading...</p>}
{error && <p>Error: {error}</p>}
{data.map((u) => (
<p key={u.id}>{u.name}</p>
))}
</div>
);
}
π That's it!
You now have:
- Redux slice
- Async thunk action creator
- Working API call
- Component consuming Redux state
If you want, I can also show:
β
same example using createAsyncThunk (shorter)
β
error handling + retries
β
RTK Query way (even simpler)
Just tell me!
Top comments (0)