Dưới đây là những cách viết code "có mùi" (Code Smells) bạn cần dọn dẹp ngay.
1. Redundant State (State thừa thãi)
Lỗi phổ biến nhất: Lưu trữ cái có thể tính toán được vào State.
// ❌ BAD: Dư thừa
const [firstName, setFirstName] = useState('John');
const [lastName, setLastName] = useState('Doe');
const [fullName, setFullName] = useState('John Doe'); // Tại sao phải lưu cái này?
useEffect(() => {
setFullName(`${firstName} ${lastName}`);
}, [firstName, lastName]);Khi bạn set firstName, component render -> useEffect chạy -> Set fullName -> Render lại lần nữa (2 lần render).
// ✅ GOOD: Derived State
const [firstName, setFirstName] = useState('John');
const [lastName, setLastName] = useState('Doe');
// Tính trực tiếp trong render
const fullName = `${firstName} ${lastName}`;Biến fullName sẽ luôn tươi mới mỗi lần render. Không cần sync.
2. useEffect để Fetch Data (Waterfall)
Fetch trong component con nối đuôi nhau.
// ❌ Component A fetch xong mới render B -> B mới bắt đầu fetch
<User>
<Posts>
<Comments />
</Posts>
</User>Fix: Data Fetching nên được đưa lên cao (Route Level) hoặc dùng Promise.all.
3. Prop Drilling (Khoan cắt bê tông)
Truyền props qua 5-6 tầng component trung gian không dùng props đó.
Fix: Dùng Composition (children prop) hoặc Context API.
4. God Components (Component Chúa)
Một file Dashboard.tsx dài 2000 dòng, chứa logic của cả Auth, Data Fetching, UI Chart, Table...
Fix:
- Tách nhỏ UI (Sub-components).
- Tách Logic ra Custom Hooks (
useDashboardData).
5. Index as Key
// ❌ Nguy hiểm nếu list có thể thay đổi thứ tự/xóa
{items.map((item, index) => <li key={index}>{item}</li>)}Nếu bạn xóa item đầu tiên, React sẽ tưởng item đầu tiên bị đổi nội dung chứ không phải bị xóa -> Bug UI input/state.
Fix: Luôn dùng ID duy nhất (item.id).
Kết luận
Code React đẹp là code:
- Ít
useEffect. - Ít
useState(chỉ lưu cái tối thiểu). - Component nhỏ, đơn nhiệm (Single Responsibility).