Đừng Dùng useState Cho Mọi Thứ: 5 Lỗi Phổ Biến Khiến App React Của Bạn Chậm Chạp

Đừng Dùng useState Cho Mọi Thứ: 5 Lỗi Phổ Biến Khiến App React Của Bạn Chậm Chạp
useState là hook phổ biến nhất React, nhưng lạm dụng nó có thể khiến ứng dụng chậm, lag, re-render vô ích. Khám phá 5 lỗi thường gặp và cách khắc phục bằng useMemo, useReducer, useDeferredValue, state colocation… để app React mượt mà hơn năm 2026.
Giới thiệu
useState là hook đầu tiên mà hầu hết developer React học. Nó đơn giản, dễ dùng… và cũng là “thủ phạm” khiến rất nhiều ứng dụng React trở nên chậm chạp, tiêu tốn CPU và làm người dùng khó chịu.
Nhiều lập trình viên có thói quen dùng useState cho mọi thứ – từ dữ liệu tính toán được, state form phức tạp, cho đến giá trị không thay đổi. Kết quả là component re-render liên tục, thậm chí gây bottleneck nghiêm trọng.
Bài viết này sẽ chỉ ra 5 lỗi phổ biến nhất liên quan đến useState và cách khắc phục đúng chuẩn best practices React 2026.
1. Lưu giá trị tính toán được vào useState (Lỗi nghiêm trọng nhất)
Vấn đề:
Bạn fetch data rồi tính toán thêm (filter, sort, map…) và lưu kết quả vào state.
const [filteredUsers, setFilteredUsers] = useState([]);
useEffect(() => {
const result = users.filter(...).sort(...);
setFilteredUsers(result); // ❌ Sai
}, [users]);
Hậu quả: State mới → component re-render → useEffect chạy lại → vòng lặp vô hạn hoặc render thừa.
Cách sửa: Dùng useMemo
const filteredUsers = useMemo(() => {
return users.filter(...).sort(...);
}, [users]);
Quy tắc: Nếu giá trị có thể tính toán từ state khác → dùng useMemo, không dùng useState.
2. Tạo object, array, function mới mỗi lần render
Đây là nguyên nhân phổ biến gây re-render cascade ở child components.
Code sai:
const [user, setUser] = useState(...);
const config = { theme: 'dark', user }; // ❌ object mới mỗi render
const handleSave = () => { ... }; // ❌ function mới mỗi render
<Child config={config} onSave={handleSave} />
Cách sửa đúng:
const config = useMemo(() => ({ theme: 'dark', user }), [user]);
const handleSave = useCallback(() => {
// ...
}, []);
<Child config={config} onSave={handleSave} />
Mẹo: Luôn memoize object/array/function khi truyền xuống component con.
3. Dùng một useState khổng lồ cho toàn bộ form hoặc state phức tạp
const [formData, setFormData] = useState({
name: '', email: '', address: '', company: '', ... // 20 fields
});
Mỗi lần gõ một chữ → toàn bộ component + tất cả children re-render.
Giải pháp:
- Tách state nhỏ (State Colocation)
- Dùng
useReducercho state logic phức tạp - Hoặc dùng thư viện: Zustand, Jotai, React Hook Form + Zod
// Tốt hơn
const [name, setName] = useState('');
const [email, setEmail] = useState('');
4. Không phân biệt state "khẩn cấp" và state "không khẩn cấp"
Ví dụ: Search input → filter danh sách lớn.
Mỗi lần gõ chữ → state update → re-render ngay lập tức → app lag.
Giải pháp: Dùng useDeferredValue (React 18+)
const [query, setQuery] = useState('');
const deferredQuery = useDeferredValue(query);
const filtered = useMemo(() => heavyFilter(deferredQuery), [deferredQuery]);
Hoặc dùng useTransition cho các cập nhật không ưu tiên:
const [isPending, startTransition] = useTransition();
startTransition(() => {
setHeavyState(newValue);
});
5. Dùng useState thay vì useReducer khi state có logic phức tạp
Khi state có nhiều action liên quan nhau (add, remove, update, reset, validate…):
// ❌ Bad
const [cart, setCart] = useState([]);
const addToCart = ...
const removeFromCart = ...
const updateQuantity = ...
Cách đúng:
const [cart, dispatch] = useReducer(cartReducer, initialState);
dispatch({ type: 'ADD_TO_CART', payload: item });
Lợi ích: Logic tập trung, dễ test, dễ debug, ít re-render hơn khi kết hợp useMemo và useCallback.
Bảng tóm tắt: Nên dùng gì thay vì useState?
| Trường hợp | Nên dùng thay thế | Lý do chính |
|---|---|---|
| Giá trị tính toán từ state khác | useMemo | Tránh re-compute |
| Object/Array/Function truyền props | useMemo + useCallback | Ngăn re-render con |
| Form có nhiều field | Tách state / React Hook Form | Giảm re-render |
| Update không khẩn cấp | useDeferredValue / useTransition | Giữ UI mượt |
| State logic phức tạp | useReducer | Code rõ ràng, dễ quản lý |
| State toàn cục | Zustand / Jotai / Redux Toolkit | Tránh prop drilling |
Kết luận & Lời khuyên thực tế
useState rất tốt, nhưng không phải là giải pháp cho mọi thứ.
Hãy hình thành thói quen:
- Hỏi bản thân: “Giá trị này có cần lưu trong state không hay chỉ tính toán được?”
- Luôn memoize thứ truyền xuống component con.
- Tách state nhỏ nhất có thể.
- Dùng công cụ phù hợp cho từng loại state.
Áp dụng đúng các nguyên tắc trên, bạn sẽ thấy app React mượt hơn rõ rệt, Core Web Vitals cải thiện và ít bug hơn rất nhiều.
Bạn đang gặp vấn đề performance với useState ở đâu?
Comment bên dưới lỗi bạn hay gặp nhất (form, danh sách lớn, modal, dashboard…), mình sẽ đưa ví dụ code cụ thể để tối ưu.
Tags:
useState React, tối ưu performance React, useMemo useCallback, useReducer React, React re-render, React best practices 2026, fix slow React app, React performance