📄 Redux Toolkit Tutorial 02

📘 Redux Toolkit: React āĻĄā§‡āϭ⧇āϞāĻĒāĻžāϰāĻĻ⧇āϰ āϜāĻ¨ā§āϝ āĻāĻ•āϟāĻŋ āĻĒā§‚āĻ°ā§āĻŖāĻžāĻ™ā§āĻ— āĻ—āĻžāχāĻĄ


āϏ⧇āĻ•āĻļāύ ā§§: āϕ⧇āύ Redux?

āϧāϰ⧁āύ āφāĻĒāύāĻŋ āĻāĻ•āϟāĻž E-commerce āĻ…ā§āϝāĻžāĻĒ āĻŦāĻžāύāĻžāĻšā§āϛ⧇āύ (āϝ⧇āĻŽāύ- āĻĻāĻžāϰāĻžāϜ āĻŦāĻž āφāϜāϕ⧇āϰāĻĄāĻŋāϞ āϟāĻžāχāĻĒ)āĨ¤

  • āχāωāϜāĻžāϰ āϞāĻ—āχāύ āĻ•āϰ⧇āϛ⧇ āĻ•āĻŋ āύāĻž,
  • āĻļāĻĒāĻŋāĻ‚ āĻ•āĻžāĻ°ā§āĻŸā§‡ āĻ•āϤāϗ⧁āϞ⧋ āĻĒāĻŖā§āϝ āφāϛ⧇,
  • āĻĄāĻŋāϏāĻ•āĻžāωāĻ¨ā§āϟ āϕ⧋āĻĄ āĻ•āĻžāϜ āĻ•āϰāϛ⧇ āĻ•āĻŋ āύāĻž,
  • āĻ…āĻ°ā§āĻĄāĻžāϰ āĻšāĻŋāĻ¸ā§āĻŸā§‹āϰāĻŋ—

āĻāϏāĻŦ āϤāĻĨā§āϝ āϝāĻĻāĻŋ āφāϞāĻžāĻĻāĻž āφāϞāĻžāĻĻāĻž āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āĻŸā§‡ āϰāĻžāϖ⧇āύ, āϤāĻ–āύ āĻĄā§‡āϟāĻž āĻŽā§āϝāĻžāύ⧇āϜ āĻ•āϰāĻž āĻ•āĻ āĻŋāύ āĻšā§Ÿā§‡ āϝāĻžāĻŦ⧇āĨ¤

React āĻāϰ Context API āϛ⧋āϟāĻ–āĻžāĻŸā§‹ āĻ•ā§āώ⧇āĻ¤ā§āϰ⧇ āĻ āĻŋāĻ• āφāϛ⧇, āĻ•āĻŋāĻ¨ā§āϤ⧁ āĻŦ⧜ āĻ…ā§āϝāĻžāĻĒā§āϞāĻŋāϕ⧇āĻļāύ⧇ Context āφāĻ¸ā§āϤ⧇ āφāĻ¸ā§āϤ⧇ āϜāϟāĻŋāϞ āĻšā§Ÿā§‡ āϝāĻžā§ŸāĨ¤ āĻāĻ–āĻžāύ⧇āχ Redux āφāĻĒāύāĻžāϰ āϜāĻ¨ā§āϝ āĻāĻ•āϜāύ "āϕ⧇āĻ¨ā§āĻĻā§āĻ°ā§€ā§Ÿ āĻšāĻŋāϏāĻžāĻŦāϰāĻ•ā§āώāĻ•" āĻšā§Ÿā§‡ āĻ•āĻžāϜ āĻ•āϰ⧇āĨ¤


āϏ⧇āĻ•āĻļāύ ⧍: Redux Toolkit (RTK) āϕ⧇āύ?

Redux āĻāϰ āĻŽā§‚āϞ āϏāĻŽāĻ¸ā§āϝāĻžāϗ⧁āϞ⧋ āĻšāϞ⧋:

  1. āĻ…āύ⧇āĻ• boilerplate āϕ⧋āĻĄāĨ¤
  2. āĻ•āύāĻĢāĻŋāĻ—āĻžāϰ⧇āĻļāύ āϜāϟāĻŋāϞāĨ¤
  3. Middleware āĻŽā§āϝāĻžāύ⧁⧟āĻžāϞāĻŋ āϝ⧋āĻ— āĻ•āϰāϤ⧇ āĻšā§ŸāĨ¤

Redux Toolkit (RTK) āĻāϗ⧁āϞ⧋ āϏāĻŽāĻžāϧāĻžāύ āĻ•āϰ⧇ āĻĻāĻŋā§Ÿā§‡āϛ⧇:

  • configureStore āĻĻāĻŋā§Ÿā§‡ āϏāĻšāĻœā§‡ āĻ¸ā§āĻŸā§‹āϰ āϏ⧇āϟāφāĻĒāĨ¤
  • createSlice āĻĻāĻŋā§Ÿā§‡ state, action, reducer āĻāĻ•āϏāĻžāĻĨ⧇āĨ¤
  • createAsyncThunk āĻĻāĻŋā§Ÿā§‡ āϏāĻšāĻœā§‡ async API callāĨ¤
  • RTK Query āĻĻāĻŋā§Ÿā§‡ āĻĄā§‡āϟāĻž fetching/caching āĻāĻ•āĻĻāĻŽ painlessāĨ¤

āϏ⧇āĻ•āĻļāύ ā§Š: Redux āĻāϰ āĻŽā§‚āϞ āϧāĻžāϰāĻŖāĻž

Redux āϤāĻŋāύāϟāĻž āĻŽā§ŒāϞāĻŋāĻ• āύ⧀āϤāĻŋāϰ āωāĻĒāϰ āĻĻāĻžāρ⧜āĻŋā§Ÿā§‡ āφāϛ⧇:

  1. Single source of truth → āϏāĻŦ state āĻāĻ•āϟāĻžāχ store-āĻ āĻĨāĻžāĻ•āĻŦ⧇āĨ¤
  2. State is read-only → state āϏāϰāĻžāϏāϰāĻŋ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ āĻ•āϰāĻž āϝāĻžāĻŦ⧇ āύāĻž, action āĻĻāĻŋāϤ⧇ āĻšāĻŦ⧇āĨ¤
  3. 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 āĻ•āϰāϤ⧇ āϏāĻžāĻšāĻžāĻ¯ā§āϝ āĻ•āϰ⧇āĨ¤


āϏ⧇āĻ•āĻļāύ ā§§ā§§: āĻāĻ•āϟāĻŋ āĻĒā§‚āĻ°ā§āĻŖāĻžāĻ™ā§āĻ— āĻĢā§āϰāĻ¨ā§āϟāĻāĻ¨ā§āĻĄ āĻ…ā§āϝāĻžāĻĒā§āϞāĻŋāϕ⧇āĻļāύ āϤ⧈āϰāĻŋ

📘 Redux Toolkit āĻĻāĻŋā§Ÿā§‡ āĻāĻ•āϟāĻŋ āĻĒā§‚āĻ°ā§āĻŖāĻžāĻ™ā§āĻ— āĻĢā§āϰāĻ¨ā§āϟāĻāĻ¨ā§āĻĄ āĻ…ā§āϝāĻžāĻĒā§āϞāĻŋāϕ⧇āĻļāύ āϤ⧈āϰāĻŋ
âŦ‡ī¸ Download PDF
👉 āϟāĻŋāωāĻŸā§‹āϰāĻŋ⧟āĻžāϞāϟāĻŋ PDF āφāĻ•āĻžāϰ⧇ āĻĄāĻžāωāύāϞ⧋āĻĄ āĻ•āϰ⧇ āĻĒ⧜⧁āύ 🚀

Š 2024 - 2026 React JS Bangla Tutorial.