← Về danh sách bài họcBài 20/25

🏗️ Bài 20: State Management - Quản Lý State Toàn Cục

⏱️ Thời gian đọc: 18 phút | 📚 Độ khó: Nâng cao

🎯 Sau bài học này, bạn sẽ:

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ápKhi nào dùngBundle
useStateState local đơn giản0
Context + ReducerState chia sẻ, ít cập nhật0
ZustandState toàn app, cập nhật thường xuyên~1KB
Redux ToolkitApp lớn, cần middleware, devtools~10KB
Jotai/RecoilAtomic state, derived values~3KB

📝 Tóm Tắt