- vừa được xem lúc

10 Lỗi phổ biến mà các lập trình viên mới học React hay mắc phải (Và cách khắc phục)

0 0 1

Người đăng: Vinh Phạm

Theo Viblo Asia

Sau khi làm việc với hàng chục lập trình viên và xem qua rất nhiều mã nguồn React, tôi nhận ra một mô hình lặp lại: nhiều lập trình viên viết mã chạy ổn trong quá trình phát triển, nhưng lại gây ra lỗi nhỏ và trải nghiệm người dùng khó chịu khi lên production.

Những lỗi này thường chỉ xuất hiện khi người dùng thực sự tương tác với ứng dụng, dẫn đến tỷ lệ thoát cao, mất lòng tin người dùng, thậm chí là mất doanh thu.

Trong bài viết này, tôi sẽ phân tích 10 lỗi phổ biến tôi từng thấy (và từng mắc phải), cùng với cách khắc phục thực tế. Mục tiêu: từ "chạy được trên máy tôi" đến "ai dùng cũng thấy tuyệt".

1. Không sử dụng tham số truy vấn trong URL

Lỗi gặp phải:

const [search, setSearch] = useState('');

Trạng thái chỉ được lưu trong bộ nhớ.

Vấn đề:

  • Refresh lại trang sẽ mất bộ lọc.
  • Không thể chia sẻ view đã lọc.
  • URL không phản ánh trạng thái giao diện.

Cách khắc phục: Dùng useSearchParams cho các trường hợp đơn giản:

const [searchParams, setSearchParams] = useSearchParams();
const search = searchParams.get('q') || '';

Dùng nuqs + zod để có trạng thái được kiểm tra kiểu:

import { useQueryState } from 'nuqs';
import { z } from 'zod'; const { q, setQuery } = useQueryState({ q: z.string().optional() }); const handleSearch = (value) => { setQuery({ q: value });
};

Trình duyệt coi URL là nguồn chân lý – UI của bạn cũng nên như vậy.

2. Tránh sử dụng thẻ <form>

Lỗi gặp phải:

  • Dùng div và onClick thay vì hành vi gốc của <form>.

Vấn đề:

  • Không bấm Enter được để gửi.
  • Trình đọc màn hình thiếu ngữ nghĩa.
  • Trình duyệt không kiểm tra đầu vào.

Cách khắc phục:

<form onSubmit={(e) => { e.preventDefault(); handleSubmit();
}}> <label htmlFor="name">Name:</label> <input id="name" type="text" required /> <button type="submit">Submit</button>
</form>

Thư viện như react-hook-form vẫn dựa vào <form>.

3. Gọi useState quá nhiều cho từng trường riêng biệt

Lỗi gặp phải:

const [name, setName] = useState('');
const [email, setEmail] = useState('');

Vấn đề:

  • Quản lý phức tạp hơn khi biểu mẫu mở rộng.

Cách khắc phục:

  • Sử dụng object:
const [form, setForm] = useState({ name: '', email: '' });
const updateField = (field, value) => { setForm(prev => ({ ...prev, [field]: value }));
};

Hoặc useReducer cho trường hợp phức tạp:

const initialState = { name: '', email: '' };
function reducer(state, action) { switch (action.type) { case 'UPDATE_FIELD': return { ...state, [action.field]: action.value }; default: return state; }
}
const [form, dispatch] = useReducer(reducer, initialState);

4. Không sử dụng trạng thái suy diễn (Derived State)

Lỗi gặp phải:

const [birthDate, setBirthDate] = useState('');
const [age, setAge] = useState(calculateAge(birthDate));

Vấn đề:

  • Trạng thái bị lặp, dẫn đến lỗi sai hoặc lỗi thời.

Cách khắc phục:

const age = calculateAge(birthDate);

Chỉ dùng useMemo cho tính toán nặng:

const sortedItems = useMemo(() => { return items.sort((a, b) => a.name.localeCompare(b.name));
}, [items]);

5. Dùng useMemo không đúng cách

Lỗi gặp phải:

const memoized = useMemo(() => doSomething(input), [valueThatChangesOnEveryRender]);

Vấn đề:

  • Chạy lại trên mỗi lần render – vô nghĩa.

Cách khắc phục:

Chỉ dùng useMemo khi:

  • Tính toán nặng.
  • Phụ thuộc ổn định.
const expensiveResult = useMemo(() => computeExpensiveValue(data), [data]);

6. Không có trạng thái Loading, lỗi, hoặc rỗng

Lỗi gặp phải:

const { data } = useQuery(...);
return <List items={data} />;

Vấn đề:

  • Không có phản hồi khi đang tải.
  • Người dùng thấy màn hình trắng khi lỗi.
  • SEO có thể index trang trống.

Cách khắc phục:

const { data, isLoading, isError, error } = useQuery(...);
if (isLoading) return <SkeletonList />;
if (isError) return <p>Error: {error.message}</p>;
if (!data?.length) return <p>No items found.</p>;
return <List items={data} />;

Dùng @tanstack/react-query để đơn giản hóa việc xử lý trạng thái.

7. Bỏ qua khả năng truy cập (Accessibility)

Lỗi gặp phải:

  • Dùng <div> thay cho <button>, bỏ label, quên alt cho ảnh.

Vấn đề:

  • Không dùng được bàn phím để điều hướng.
  • Trình đọc màn hình không hiểu được UI.

Cách khắc phục:

<label htmlFor="username">Username:</label>
<input id="username" type="text" /> <button aria-expanded={isOpen} onClick={toggle}>Toggle</button>

Thêm alt cho ảnh, kiểm tra với bàn phím. Dùng eslint-plugin-jsx-a11y hoặc axe.

8. Không Debounce dữ liệu đầu vào

Lỗi gặp phải:

<input value={query} onChange={e => setQuery(e.target.value)} />

Vấn đề:

  • Cập nhật đắt đỏ xảy ra trên mỗi lần gõ phím.

Cách khắc phục:

Dùng hook debounce:

function useDebounce(value, delay) { const [debounced, setDebounced] = useState(value); useEffect(() => { const id = setTimeout(() => setDebounced(value), delay); return () => clearTimeout(id); }, [value, delay]); return debounced;
}

Hoặc dùng useDeferredValue (React 18+) để chuyển trạng thái mượt hơn.

9. Form nhiều bước bị Reset khi Quay Lại

Lỗi gặp phải:

  • Mỗi bước lưu trạng thái riêng.

Vấn đề:

  • Quay lại bước trước sẽ mất dữ liệu người dùng đã nhập.

Cách khắc phục:

  • Lưu trạng thái ở component cha:
const [formState, setFormState] = useState({ name: '', email: '' });

Truyền state và hàm cập nhật xuống từng bước. Với ứng dụng lớn, dùng react-hook-form hoặc zustand.

10. Không có Skeleton hoặc Placeholder

Lỗi gặp phải:

return isLoading ? null : <ActualList items={data} />;

Vấn đề:

  • Màn hình trắng gây hoang mang. Hiệu suất cảm nhận kém.

Cách khắc phục:

function SkeletonList() { return ( <div> {[...Array(3)].map((_, i) => ( <div key={i} style={{ height: '50px', background: '#e0e0e0', marginBottom: '8px' }} /> ))} </div> );
}

Skeleton giúp cung cấp phản hồi trực quan và tránh giật layout.

Lời kết Trải nghiệm người dùng kém thường bắt nguồn từ những lỗi nhỏ trong mã nguồn. Những lỗi này có thể không xuất hiện khi phát triển cục bộ, nhưng sẽ gây khó chịu cho người dùng thật.

Viết code nên bền vững với việc refresh, tương thích với URL, và thể hiện sự thấu cảm với các trường hợp đặc biệt.

Không ai cần phải hoàn hảo. Quan trọng là phải suy nghĩ thấu đáo.

Tôi cũng từng mắc những lỗi này — và tôi đã học được từ chúng.

Còn bạn thì sao? Bạn đã từng mắc lỗi nào trong số này? Hãy chia sẻ câu chuyện hoặc thắc mắc của bạn nhé, tôi rất muốn nghe!

Bình luận

Bài viết tương tự

- vừa được xem lúc

Tìm hiểu về Redux Thunk

Chào mọi người, nếu bạn là người đã biết về React và đang làm quen với Redux chắc hẳn bạn đang rất mơ hồ về các khái niệm cơ bản của Redux như dispatch, store, action creator,... bạn còn đang vật lộn với đống document của Redux để hiểu những khái niệm đó và bạn nghe ai đó trong team nói về Redux Thu

0 0 412

- vừa được xem lúc

[React] Giới thiệu tổng quát về Redux Toolkit

1. Redux Toolkit (RTK) là gì và tại sao lại có nó. . .

0 0 6.7k

- vừa được xem lúc

Uống Pepsi code Vue đi - Uống Cocacola code React nha ;)

. (Nguồn ảnh: Internet). Chào các bạn, chào các bạn. Let's go . 1.

0 0 158

- vừa được xem lúc

Cài đặt taillwind css cho dự án React

Trong bài viết cùng mình tìm hiểu cách cài đặt tailwind css cho một dự án React sẵn có. .

0 0 157

- vừa được xem lúc

Formik vs React Hook Form (Phần 1)

Các lập trình viên Front End đều làm việc rất nhiều với form cùng sự phức tạp của ứng dụng. Do vậy chúng ta cần những thư viện form mạnh mẽ hỗ trợ quản lý các form state, form validation... Thành phần module. Formik bao gồm có 9 dependencies khác. . React Hook Form thì không có.

0 0 382

- vừa được xem lúc

Hướng dẫn React Redux cho người mới bắt đầu - Phần 1

Lời mởi đầu. Chào các bạn, ở thời điểm thực hiện bài viết này mình cũng là một người đang bắt đầu tìm hiểu và học với ReactJs và Redux, trong quá trình tìm hiểu đọc các tài liệu về thư viện này mình có tìm được một bài hướng dẫn khá hay nên đã quyết định chia sẻ với mọi người .

0 0 293