NgRx คือแนวทางจัดการ State ของ Angular โดยใช้แนวคิด Store กลาง ทำให้ข้อมูลสำคัญของแอปมี Single Source of Truth และติดตามการเปลี่ยนแปลงผ่าน Action ได้ชัดเจน
%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#fabd2f", "primaryTextColor": "#282828", "primaryBorderColor": "#b57614", "lineColor": "#7c6f64", "secondaryColor": "#83a598", "tertiaryColor": "#b8bb26", "background": "#fbf1c7", "mainBkg": "#ebdbb2", "fontFamily": "Tahoma, sans-serif"}}}%%
flowchart LR
subgraph Era1["ยุค Local State / Component State"]
A["ข้อมูลอยู่หลาย Component
Debug ยาก"]
end
subgraph Era2["ยุค Store Pattern / Central Store"]
B["Store
Single Source of Truth"]
C["Action + Reducer
เปลี่ยน State แบบคาดเดาได้"]
end
subgraph Era3["ยุค Side Effects / Reactive State"]
D["Effect
จัดการ HTTP"]
E["Selector
ดึงข้อมูลเพื่อแสดงผล"]
end
A --> B --> C --> D --> E
[User] Load Usersstore.dispatch(action) ใช้ส่ง Actionstore.select(selector) ใช้อ่าน State| องค์ประกอบ | หน้าที่ | ตัวอย่าง |
|---|---|---|
| Store | เก็บ State กลาง | users, loading |
| Action | บอกว่าเกิดอะไรขึ้น | loadUsers |
| Reducer | สร้าง State ใหม่ | set loading true |
| Selector | อ่าน State | selectAllUsers |
| Effect | จัดการ API | call HttpClient |
%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#fabd2f", "primaryTextColor": "#282828", "primaryBorderColor": "#b57614", "lineColor": "#7c6f64", "secondaryColor": "#83a598", "tertiaryColor": "#b8bb26", "background": "#fbf1c7", "mainBkg": "#ebdbb2", "fontFamily": "Tahoma, sans-serif"}}}%%
flowchart LR
A["Component
หน้าจอ"] -->|dispatch Action| B["Action
เหตุการณ์"]
B --> C["Reducer
สร้าง State ใหม่"]
C --> D["Store
State กลาง"]
D -->|select Selector| A
B --> E["Effect
เรียก API"]
E --> F["HTTP API
Server"]
F --> E -->|success/failure Action| B
// user.actions.ts
// Action อธิบายเหตุการณ์ในระบบ
import { createAction, props } from '@ngrx/store';
export const loadUsers = createAction('[User] Load Users');
export const loadUsersSuccess = createAction(
'[User] Load Users Success',
props<{ users: User[] }>()
);
export const loadUsersFailure = createAction(
'[User] Load Users Failure',
props<{ error: string }>()
);
// user.reducer.ts
// Reducer ต้องเป็น pure function และคืน state ใหม่เสมอ
import { createReducer, on } from '@ngrx/store';
import { loadUsers, loadUsersFailure, loadUsersSuccess } from './user.actions';
export interface UserState {
users: User[];
loading: boolean;
error: string | null;
}
export const initialState: UserState = {
users: [],
loading: false,
error: null
};
export const userReducer = createReducer(
initialState,
on(loadUsers, state => ({ ...state, loading: true })),
on(loadUsersSuccess, (state, { users }) => ({ ...state, users, loading: false })),
on(loadUsersFailure, (state, { error }) => ({ ...state, error, loading: false }))
);
// ตัวอย่างการใช้งาน:
// this.store.dispatch(loadUsers());
// user.selectors.ts
// Selector ดึงข้อมูลเฉพาะส่วนที่ Component ต้องใช้
import { createFeatureSelector, createSelector } from '@ngrx/store';
export const selectUserState = createFeatureSelector<UserState>('users');
export const selectAllUsers = createSelector(selectUserState, state => state.users);
export const selectUsersLoading = createSelector(selectUserState, state => state.loading);
loadLessons