Context
SSD uses Redux Toolkit for global state management in React. Every module with global state must create its own slice and add it to the rootReducer at src/redux/rootReducer.ts
How Redux Works
Redux works through 3 main parts:
- Store — the store that holds all state data
- Action — an instruction with a payload sent to the reducer to change state
- Reducer — the process of changing state according to an action
Components work with Redux using:
- Subscribe (
useAppSelector) — receives state values from the store - Dispatch (
useAppDispatch) — sends actions to the reducer
Main Rules
- Must create a slice in
src/app/modules/[ModuleName]/[moduleName]Slice.ts - Must export the type of State and Payload every time
- Must export
actions,reducer, and may exportselector - Must add the reducer to the rootReducer in
src/redux/rootReducer.ts - Must use
useAppSelectoranduseAppDispatchfromsrc/redux/hook.tsonly
Step 1: Create a Slice
Create a file at src/app/modules/[ModuleName]/[moduleName]Slice.ts
// src/app/modules/counter/counterSlice.ts
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
// 1. สร้าง Type ของ State (ต้องทำ)
export type CounterState = {
count: number;
settings: {
showCount: boolean;
};
};
// 2. กำหนดค่าเริ่มต้น (ต้องทำ)
const initialState: CounterState = {
count: 0,
settings: {
showCount: true,
},
};
// 3. สร้าง Type ของ Payload สำหรับ action ที่มีหลายตัวแปร (ควรทำ)
// ตั้งชื่อตาม Action และลงท้ายด้วย Payload
export type SetShowCountPayload = {
count: number;
showCount: boolean;
};
// 4. สร้าง Slice (ต้องทำ)
const counterSlice = createSlice({
name: "counter", // ชื่อ slice ควรเป็นชื่อ Module
initialState,
reducers: {
setCount: (state, action: PayloadAction<number>) => {
state.count = action.payload;
},
setShowCount: (state, action: PayloadAction<SetShowCountPayload>) => {
state.count = action.payload.count;
state.settings.showCount = action.payload.showCount;
},
},
});
// 5. Export actions (ต้องทำ)
export const { setCount, setShowCount } = counterSlice.actions;
// 6. Export selector (ไม่จำเป็น แต่แนะนำ)
export const countSelector = (state: RootState) => state.counter;
// 7. Export reducer (ต้องทำ)
export default counterSlice.reducer;
If there are multiple slices in the same module
Name it in the style [moduleName][SubModule]Slice.ts such as orderDetailSlice.ts, orderListSlice.ts
Step 2: Add to rootReducer
Edit the file src/redux/rootReducer.ts:
import { counterSlice } from "../app/modules/counter/counterSlice";
import { combineReducers } from "@reduxjs/toolkit";
export const rootReducer = combineReducers({
layout: persistReducer(persistConfig, layoutSlice),
counter: counterSlice, // เพิ่ม slice ใหม่ที่นี่
});
Step 3: Use in a Component
import { useAppSelector, useAppDispatch } from "../../redux/hook";
import { setCount, setShowCount, countSelector } from "./counterSlice";
export const CounterComponent = () => {
// Subscribe ค่าจาก Redux
const { count, settings } = useAppSelector(countSelector);
// หรือ: const { count } = useAppSelector(state => state.counter);
// เรียกใช้ dispatch
const dispatch = useAppDispatch();
const handleIncrement = () => {
// dispatch action ที่มี payload เดียว
dispatch(setCount(count + 1));
};
const handleToggleShow = () => {
// dispatch action ที่ payload เป็น object
dispatch(setShowCount({
count: count,
showCount: !settings.showCount,
}));
};
return (
<div>
<h1>Count: {count}</h1>
<button onClick={handleIncrement}>เพิ่ม</button>
<button onClick={handleToggleShow}>
{settings.showCount ? "ซ่อน" : "แสดง"}
</button>
</div>
);
};
Redux File Structure
src/
├── redux/
│ ├── rootReducer.ts # รวม reducer ทั้งหมด
│ └── hook.ts # useAppSelector, useAppDispatch
└── app/modules/
└── [ModuleName]/
└── [moduleName]Slice.ts # slice ของแต่ละ module