Lỗi thường gặp
Danh sách các vi phạm convention hay gặp khi review code. Mục đích là nhận diện nhanh và tránh lặp lại; chi tiết quy tắc xem các trang TypeScript, React, Next.js và Styling.
Không comment hàm / API
Vấn đề: Hàm public, Server Action, service quan trọng không có JSDoc hoặc comment mô tả hành vi, tham số, giá trị trả về.
Cách làm đúng: Thêm JSDoc cho function/API phức tạp; type rõ ràng thì có thể ngắn gọn. Xem Comments & Formatting và Server Actions.
Inline function trong JSX
Vấn đề: Truyền onClick={() => ...} hoặc onChange={(e) => ...} trực tiếp trong JSX khiến tạo hàm mới mỗi lần render, dễ gây re-render không cần thiết ở component con được memo.
Cách làm đúng: Dùng useCallback khi truyền xuống component tối ưu; hoặc tách handler ra biến/hàm có tên. Xem Hooks & useEffect và Styling - UI rules.
Inline style
Vấn đề: Dùng style={{ ... }} rải rác trong component thay vì class Tailwind/CSS module.
Cách làm đúng: Dùng class (Tailwind, CSS module), tránh inline style trừ trường hợp giá trị thực sự động (ví dụ width theo prop). Xem UI rules.
Không dùng cn (clsx + tailwind-merge)
Vấn đề: Ghép chuỗi class hoặc template string khiến class Tailwind xung đột (cùng thuộc tính) không được merge đúng; hoặc điều kiện class dài khó đọc.
Cách làm đúng: Dùng helper cn (clsx + tailwind-merge) để gộp class có điều kiện và resolve xung đột.
// bad
<div className={`px-4 py-2 ${active ? 'bg-blue-500' : 'bg-gray-200'}`} />
// good
import { cn } from '@/lib/utils';
<div className={cn('px-4 py-2', active ? 'bg-blue-500' : 'bg-gray-200')} />
Import không đúng quy ước
Vấn đề: Import sâu từng file thay vì barrel; import từ app/; barrel import không cần thiết gây bundle lớn; đường dẫn alias không thống nhất.
Cách làm đúng: Import qua index.ts khi team quy định; không import từ thư mục app cho shared code; dùng alias @/ thống nhất. Xem Modules.
Không có loading / skeleton
Vấn đề: Màn hình fetch dữ liệu nhưng không hiển thị trạng thái đang tải — user thấy trống hoặc nhảy layout.
Cách làm đúng: Dùng Skeleton (hoặc spinner có chủ đích) phản ánh layout nội dung. Xem Loading & Empty State.
Không có empty state
Vấn đề: Danh sách rỗng hoặc không có kết quả tìm kiếm nhưng không có message/CTA.
Cách làm đúng: Component Empty State rõ ràng (message + hành động nếu cần). Xem Loading & Empty State.
Không phân quyền trên Server Action / API
Vấn đề: Chỉ ẩn nút trên UI nhưng Action không kiểm tra quyền — user có thể gọi trực tiếp và thực hiện thao tác không được phép.
Cách làm đúng: Luôn kiểm tra auth/org/role trong Action (hoặc layer tương đương) trước khi thực hiện. Xem Authorization.
Tóm tắt checklist nhanh
| Lỗi thường gặp | Hành động |
|---|---|
| Thiếu comment hàm/API | Bổ sung JSDoc / comment |
| Inline function trong JSX | useCallback hoặc handler tách riêng |
| Inline style | Class + Tailwind / CSS module |
| Class Tailwind xung đột | Dùng cn + tailwind-merge |
| Import lộn xộn | Barrel, alias, không import từ app |
| Không loading | Skeleton / trạng thái tải |
| Không empty state | Empty State component |
| Không phân quyền backend | Kiểm tra trong Server Action |