Khi bạn giữ vai trò cố vấn cũng như đầu tàu về các quyết định về phía Frontend, state management không còn là việc chọn thư viện nào ngon nhất, mà là đưa ra quyết định kiến trúc phù hợp với bài toán kinh doanh. Tôi đã từng chứng kiến nhiều dự án tốn hàng trăm giờ dev chỉ để maintain Redux boilerplate không cần thiết. Bài viết này sẽ chia sẻ góc nhìn thực chiến của tôi sau 7 năm làm FE.
1. Câu Hỏi Cốt Lõi Trước Khi Chọn Công Cụ
Tôi luôn bắt đầu bằng những câu hỏi kinh doanh:
-
"State này có thực sự cần global không?"
→ 70% state trong app thực chất chỉ cần local (useState là đủ) -
"Team size bao nhiêu? Có bao nhiêu dev sẽ cùng modify state này?"
→ Redux phù hợp khi có 5+ dev cùng làm, Zustand/Jotai tốt cho team nhỏ -
"Ứng dụng có cần real-time updates không?"
→ WebSocket + Signals/SolidJS hiệu quả hơn Redux -
"Product có yêu cầu offline-first không?"
→ Xem xét thư viện có persist middleware (Zustand, Redux-Persist)
2. Những Sai Lầm Tôi Đã Từng Mắc Phải
2.1 Áp Dụng Redux Cho Mọi Thứ
Năm 2020, tôi lead một dự án startup dùng Redux cho toàn bộ state, kể cả form input. Kết quả:
- Tốn 3 ngày chỉ để setup store
- Mỗi lần gõ form gây re-render cả app
- Bài học: Đừng dùng dao mổ trâu để giết muỗi
2.2 Không Chuẩn Hóa State Structure
Một dự án khác bị "state chaos" khi:
- Cùng 1 user data nhưng lưu ở 3 nơi khác nhau
- Không rõ đâu là single source of truth
- Giải pháp hiện tại: Luôn dùng normalizer (ví dụ: normalizr) cho API response
3. Chiến Lược Tối Ưu State Management
3.1 Phân Tầng State Rõ Ràng
Tôi chia state thành 4 lớp:
Layer | Công Cụ | Ví Dụ |
---|---|---|
Local State | useState/useReducer | Form input, toggle modal |
Domain State | Zustand/Jotai | User auth, cart items |
App State | Redux Toolkit | Feature flags, routing |
Server State | React Query/SWR | API caching |
3.2 Performance Optimization
Một trick tôi hay dùng để tránh re-render:
// Thay vì:
const { user } = useStore(); // Re-render khi bất kỳ state nào thay đổi // Hãy dùng:
const user = useStore(state => state.user); // Chỉ re-render khi user thay đổi
3.3 Type Safety Từ Đầu
Là Principal Engineer, tôi luôn enforce strict TypeScript:
// Zustand với TypeScript
interface StoreState { user: User | null; setUser: (user: User) => void;
} const useStore = create<StoreState>()((set) => ({ user: null, setUser: (user) => set({ user }),
}));
4. Case Study: Migrate Từ Redux Sang Zustand
Bài toán: Một ứng dụng B2B đang dùng Redux với:
- 50+ actions
- 30 reducers
- Tốn 5s mỗi lần dispatch complex action
Giải pháp của tôi:
- Chuyển các state không cần time-travel sang Zustand
- Giữ Redux cho undo/redo feature
- Setup selectors với memoization
Kết quả:
- Giảm 60% code lượng
- Tốc độ dispatch nhanh hơn 3x
- Dev mới onboard nhanh hơn 2 tuần
Lời Khuyên của tôi
- Đừng chạy theo xu hướng mới nhất nếu hệ thống hiện tại vẫn hoạt động tốt
- Document rõ state flow bằng diagram (tôi dùng Miro hoặc Excalidraw)
- Thiết kế cho tương lai: Luôn nghĩ đến việc chia tách state khi app scale