Đừ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

08/04/2026
5 phút đọc
0 lượt xem
Đừ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 useReducer cho 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 useMemouseCallback.


Bảng tóm tắt: Nên dùng gì thay vì useState?

Trường hợpNên dùng thay thếLý do chính
Giá trị tính toán từ state khácuseMemoTránh re-compute
Object/Array/Function truyền propsuseMemo + useCallbackNgăn re-render con
Form có nhiều fieldTách state / React Hook FormGiảm re-render
Update không khẩn cấpuseDeferredValue / useTransitionGiữ UI mượt
State logic phức tạpuseReducerCode rõ ràng, dễ quản lý
State toàn cụcZustand / Jotai / Redux ToolkitTrá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

XV

Tác giả: Xuân Vũ

Chia sẻ kiến thức về lập trình Fullstack. Hy vọng bài viết này hữu ích cho bạn!