đ Redux Toolkit: React āĻĄā§āĻā§āϞāĻĒāĻžāϰāĻĻā§āϰ āĻāύā§āϝ āĻāĻāĻāĻŋ āĻĒā§āϰā§āĻŖāĻžāĻā§āĻ āĻāĻžāĻāĻĄ
āϏā§āĻāĻļāύ ā§§: āĻā§āύ Redux?
āϧāϰā§āύ āĻāĻĒāύāĻŋ āĻāĻāĻāĻž E-commerce āĻ ā§āϝāĻžāĻĒ āĻŦāĻžāύāĻžāĻā§āĻā§āύ (āϝā§āĻŽāύ- āĻĻāĻžāϰāĻžāĻ āĻŦāĻž āĻāĻāĻā§āϰāĻĄāĻŋāϞ āĻāĻžāĻāĻĒ)āĨ¤
- āĻāĻāĻāĻžāϰ āϞāĻāĻāύ āĻāϰā§āĻā§ āĻāĻŋ āύāĻž,
- āĻļāĻĒāĻŋāĻ āĻāĻžāϰā§āĻā§ āĻāϤāĻā§āϞ⧠āĻĒāĻŖā§āϝ āĻāĻā§,
- āĻĄāĻŋāϏāĻāĻžāĻāύā§āĻ āĻā§āĻĄ āĻāĻžāĻ āĻāϰāĻā§ āĻāĻŋ āύāĻž,
- āĻ āϰā§āĻĄāĻžāϰ āĻšāĻŋāϏā§āĻā§āϰāĻŋâ
āĻāϏāĻŦ āϤāĻĨā§āϝ āϝāĻĻāĻŋ āĻāϞāĻžāĻĻāĻž āĻāϞāĻžāĻĻāĻž āĻāĻŽā§āĻĒā§āύā§āύā§āĻā§ āϰāĻžāĻā§āύ, āϤāĻāύ āĻĄā§āĻāĻž āĻŽā§āϝāĻžāύā§āĻ āĻāϰāĻž āĻāĻ āĻŋāύ āĻšā§ā§ āϝāĻžāĻŦā§āĨ¤
React āĻāϰ Context API āĻā§āĻāĻāĻžāĻā§ āĻā§āώā§āϤā§āϰ⧠āĻ āĻŋāĻ āĻāĻā§, āĻāĻŋāύā§āϤ⧠āĻŦā§ āĻ ā§āϝāĻžāĻĒā§āϞāĻŋāĻā§āĻļāύ⧠Context āĻāϏā§āϤ⧠āĻāϏā§āϤ⧠āĻāĻāĻŋāϞ āĻšā§ā§ āϝāĻžā§āĨ¤ āĻāĻāĻžāύā§āĻ Redux āĻāĻĒāύāĻžāϰ āĻāύā§āϝ āĻāĻāĻāύ "āĻā§āύā§āĻĻā§āϰā§ā§ āĻšāĻŋāϏāĻžāĻŦāϰāĻā§āώāĻ" āĻšā§ā§ āĻāĻžāĻ āĻāϰā§āĨ¤
āϏā§āĻāĻļāύ ⧍: Redux Toolkit (RTK) āĻā§āύ?
Redux āĻāϰ āĻŽā§āϞ āϏāĻŽāϏā§āϝāĻžāĻā§āϞ⧠āĻšāϞā§:
- āĻ āύā§āĻ boilerplate āĻā§āĻĄāĨ¤
- āĻāύāĻĢāĻŋāĻāĻžāϰā§āĻļāύ āĻāĻāĻŋāϞāĨ¤
- Middleware āĻŽā§āϝāĻžāύā§ā§āĻžāϞāĻŋ āϝā§āĻ āĻāϰāϤ⧠āĻšā§āĨ¤
Redux Toolkit (RTK) āĻāĻā§āϞ⧠āϏāĻŽāĻžāϧāĻžāύ āĻāϰ⧠āĻĻāĻŋā§ā§āĻā§:
configureStoreāĻĻāĻŋā§ā§ āϏāĻšāĻā§ āϏā§āĻā§āϰ āϏā§āĻāĻāĻĒāĨ¤createSliceāĻĻāĻŋā§ā§ state, action, reducer āĻāĻāϏāĻžāĻĨā§āĨ¤createAsyncThunkāĻĻāĻŋā§ā§ āϏāĻšāĻā§ async API callāĨ¤- RTK Query āĻĻāĻŋā§ā§ āĻĄā§āĻāĻž fetching/caching āĻāĻāĻĻāĻŽ painlessāĨ¤
āϏā§āĻāĻļāύ ā§Š: Redux āĻāϰ āĻŽā§āϞ āϧāĻžāϰāĻŖāĻž
Redux āϤāĻŋāύāĻāĻž āĻŽā§āϞāĻŋāĻ āύā§āϤāĻŋāϰ āĻāĻĒāϰ āĻĻāĻžāĻā§āĻŋā§ā§ āĻāĻā§:
- Single source of truth â āϏāĻŦ state āĻāĻāĻāĻžāĻ store-āĻ āĻĨāĻžāĻāĻŦā§āĨ¤
- State is read-only â state āϏāϰāĻžāϏāϰāĻŋ āĻĒāϰāĻŋāĻŦāϰā§āϤāύ āĻāϰāĻž āϝāĻžāĻŦā§ āύāĻž, action āĻĻāĻŋāϤ⧠āĻšāĻŦā§āĨ¤
- Changes via pure functions â reducer āĻĢāĻžāĻāĻļāύā§āϰ āĻŽāĻžāϧā§āϝāĻŽā§ state āĻāĻĒāĻĄā§āĻ āĻšāĻŦā§āĨ¤
āϏā§āĻāĻļāύ ā§Ē: Redux Toolkit āϏā§āĻā§āĻĒ-āĻŦāĻžāĻ-āϏā§āĻā§āĻĒ
āϧāĻžāĻĒ ā§§: āĻĒā§āϰāĻā§āĻā§āĻ āϤā§āϰāĻŋ āĻ āĻāύāϏā§āĻāϞā§āĻļāύ
npx create-react-app rtk-world-class
cd rtk-world-class
npm install @reduxjs/toolkit react-reduxāϧāĻžāĻĒ ā§¨: Store āĻāύāĻĢāĻŋāĻāĻžāϰ āĻāϰāĻž
đ src/app/store.js
import { configureStore } from "@reduxjs/toolkit";
import authReducer from "../features/auth/authSlice";
import cartReducer from "../features/cart/cartSlice";
export const store = configureStore({
reducer: {
auth: authReducer,
cart: cartReducer,
},
});āϧāĻžāĻĒ ā§Š: Provider āĻĻāĻŋā§ā§ Store āϝā§āĻā§āϤ āĻāϰāĻž
đ src/index.js
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { Provider } from "react-redux";
import { store } from "./app/store";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<Provider store={store}>
<App />
</Provider>
);āϏā§āĻāĻļāύ ā§Ģ: Slice āϤā§āϰāĻŋ āĻāϰāĻž
Slice = state + reducer + action āĻāĻāϏāĻžāĻĨā§āĨ¤
āĻāĻĻāĻžāĻšāϰāĻŖ ā§§: Auth Slice
đ src/features/auth/authSlice.js
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
user: null,
isLoggedIn: false,
};
const authSlice = createSlice({
name: "auth",
initialState,
reducers: {
login: (state, action) => {
state.user = action.payload;
state.isLoggedIn = true;
},
logout: (state) => {
state.user = null;
state.isLoggedIn = false;
},
},
});
export const { login, logout } = authSlice.actions;
export default authSlice.reducer;āĻāĻĻāĻžāĻšāϰāĻŖ ⧍: Cart Slice
đ src/features/cart/cartSlice.js
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
items: [],
};
const cartSlice = createSlice({
name: "cart",
initialState,
reducers: {
addToCart: (state, action) => {
state.items.push(action.payload);
},
removeFromCart: (state, action) => {
state.items = state.items.filter((item) => item.id !== action.payload);
},
clearCart: (state) => {
state.items = [];
},
},
});
export const { addToCart, removeFromCart, clearCart } = cartSlice.actions;
export default cartSlice.reducer;āϏā§āĻāĻļāύ ā§Ŧ: Component āĻ āĻŦā§āϝāĻŦāĻšāĻžāϰ
đ src/components/Navbar.js
import React from "react";
import { useSelector, useDispatch } from "react-redux";
import { logout } from "../features/auth/authSlice";
function Navbar() {
const { user, isLoggedIn } = useSelector((state) => state.auth);
const cartItems = useSelector((state) => state.cart.items);
const dispatch = useDispatch();
return (
<nav style={{ display: "flex", justifyContent: "space-between" }}>
<h2>đ RTK Shop</h2>
<div>
{isLoggedIn ? (
<>
<span>đ¤ {user.name}</span>
<button onClick={() => dispatch(logout())}>Logout</button>
</>
) : (
<span>Please Login</span>
)}
<span> | Cart: {cartItems.length}</span>
</div>
</nav>
);
}
export default Navbar;āϏā§āĻāĻļāύ ā§: AsyncThunk (API Call)
āϧāϰā§āύ, āĻāĻŽāϰāĻž product list API āĻĨā§āĻā§ āĻāύāĻŦāĨ¤
đ src/features/products/productsSlice.js
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
export const fetchProducts = createAsyncThunk("products/fetch", async () => {
const res = await fetch("https://fakestoreapi.com/products");
return await res.json();
});
const productsSlice = createSlice({
name: "products",
initialState: { items: [], status: "idle", error: null },
reducers: {},
extraReducers: (builder) => {
builder
.addCase(fetchProducts.pending, (state) => {
state.status = "loading";
})
.addCase(fetchProducts.fulfilled, (state, action) => {
state.status = "succeeded";
state.items = action.payload;
})
.addCase(fetchProducts.rejected, (state, action) => {
state.status = "failed";
state.error = action.error.message;
});
},
});
export default productsSlice.reducer;āϏā§āĻāĻļāύ ā§Ž: RTK Query
RTK Query āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰāϞ⧠asyncThunk āϞāĻŋāĻāϤ⧠āĻšā§ āύāĻžāĨ¤
đ src/services/productsApi.js
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
export const productsApi = createApi({
reducerPath: "productsApi",
baseQuery: fetchBaseQuery({ baseUrl: "https://fakestoreapi.com/" }),
endpoints: (builder) => ({
getProducts: builder.query({
query: () => "products",
}),
}),
});
export const { useGetProductsQuery } = productsApi;āϏā§āĻāĻļāύ ⧝: Best Practices
â
Slice āĻā§āĻ āϰāĻžāĻā§āύ, āĻĒā§āϰāϤāĻŋ āĻĢāĻŋāĻāĻžāϰā§āϰ āĻāύā§āϝ āĻāϞāĻžāĻĻāĻž sliceāĨ¤
â
Redux DevTools āĻĻāĻŋā§ā§ debugging āĻāϰā§āύāĨ¤
â
Immutable state āϰāĻžāĻā§āύ (Immer āϏā§āĻŦā§āĻāĻā§āϰāĻŋā§āĻāĻžāĻŦā§ āĻšā§āϝāĻžāύā§āĻĄā§āϞ āĻāϰā§)āĨ¤
â
Async call-āĻāϰ āĻāύā§āϝ createAsyncThunk āĻŦāĻž RTK Query āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§āύāĨ¤
â
Context API āĻāĻŦāĻ Redux āĻŽāĻŋāϞāĻŋā§ā§ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰāĻŦā§āύ āύāĻžāĨ¤
āϏā§āĻāĻļāύ ā§§ā§Ļ: āĻŦāĻžāϏā§āϤāĻŦ āĻā§āĻŦāύā§āϰ āĻŦā§āϝāĻŦāĻšāĻžāϰ (Bangladesh Context)
- E-commerce (Daraz, Evaly) â Cart, Orders, Payment Status
- School Management System â Students, Teachers, Attendance
- Ride Sharing App (Pathao) â Driver, Ride Request, Payment
Redux Toolkit āĻŦā§ āĻ ā§āϝāĻžāĻĒāĻā§āϞā§āϤ⧠āϏāĻ āĻŋāĻāĻāĻžāĻŦā§ state management āĻāϰāϤ⧠āϏāĻžāĻšāĻžāϝā§āϝ āĻāϰā§āĨ¤