← Về danh sách bài họcBài 20/25
🏗️ Bài 20: State Management - Quản Lý State Toàn Cục
🎯 Sau bài học này, bạn sẽ:
- So sánh các giải pháp state management
- Dùng Context API + useReducer (mini Redux)
- Giới thiệu Redux Toolkit và Zustand
- Chọn đúng công cụ cho từng dự án
1. Context + useReducer (Mini Redux)
import { createContext, useContext, useReducer } from 'react';
// Actions
const ADD_TODO = 'ADD_TODO';
const TOGGLE_TODO = 'TOGGLE_TODO';
const DELETE_TODO = 'DELETE_TODO';
function todoReducer(state, action) {
switch (action.type) {
case ADD_TODO: return [...state, { id: Date.now(), text: action.payload, done: false }];
case TOGGLE_TODO: return state.map(t => t.id === action.payload ? { ...t, done: !t.done } : t);
case DELETE_TODO: return state.filter(t => t.id !== action.payload);
default: return state;
}
}
const TodoContext = createContext();
function TodoProvider({ children }) {
const [todos, dispatch] = useReducer(todoReducer, []);
return (
<TodoContext.Provider value={{ todos, dispatch }}>
{children}
</TodoContext.Provider>
);
}
const useTodos = () => useContext(TodoContext);
// Sử dụng
function TodoList() {
const { todos, dispatch } = useTodos();
return (
<ul>
{todos.map(todo => (
<li key={todo.id}>
<span onClick={() => dispatch({ type: TOGGLE_TODO, payload: todo.id })}
style={{ textDecoration: todo.done ? 'line-through' : 'none' }}>
{todo.text}
</span>
<button onClick={() => dispatch({ type: DELETE_TODO, payload: todo.id })}>✕</button>
</li>
))}
</ul>
);
}2. Zustand (Đề Xuất)
import { create } from 'zustand';
const useStore = create((set) => ({
count: 0,
todos: [],
increment: () => set(state => ({ count: state.count + 1 })),
addTodo: (text) => set(state => ({
todos: [...state.todos, { id: Date.now(), text, done: false }]
})),
toggleTodo: (id) => set(state => ({
todos: state.todos.map(t => t.id === id ? { ...t, done: !t.done } : t)
})),
}));
// Sử dụng - không cần Provider!
function Counter() {
const count = useStore(state => state.count);
const increment = useStore(state => state.increment);
return <button onClick={increment}>Count: {count}</button>;
}💡 Zustand ưu điểm: Không cần Provider, API đơn giản, bundle size nhỏ (1KB), tự động tối ưu re-renders, TypeScript-friendly.
3. So Sánh Các Giải Pháp
| Giải pháp | Khi nào dùng | Bundle |
|---|---|---|
| useState | State local đơn giản | 0 |
| Context + Reducer | State chia sẻ, ít cập nhật | 0 |
| Zustand | State toàn app, cập nhật thường xuyên | ~1KB |
| Redux Toolkit | App lớn, cần middleware, devtools | ~10KB |
| Jotai/Recoil | Atomic state, derived values | ~3KB |
📝 Tóm Tắt
- Context + useReducer: built-in, tốt cho app nhỏ-vừa
- Zustand: nhẹ, API đẹp, không cần Provider
- Redux Toolkit: cho app enterprise, cần time-travel debugging
- Bắt đầu đơn giản, nâng cấp khi cần