Tại sao lỗi này xảy ra
React rất khắt khe về những gì nó hiển thị trên màn hình. Nó mong đợi các kiểu dữ liệu cụ thể như phần tử JSX, chuỗi, số hoặc mảng. Khi lỗi này xuất hiện, điều đó có nghĩa là bạn đã vô tình đưa cho React một định nghĩa hàm thay vì kết quả cuối cùng mà bạn muốn hiển thị.
Hãy coi hàm là một công thức nấu ăn và phần tử JSX là món ăn. React biết cách phục vụ món ăn, nhưng nó không biết cách "render" một công thức. Lỗi này chiếm khoảng 15-20% các lỗi phổ biến mà các nhà phát triển gặp phải khi chuyển từ JavaScript thuần sang React.
Bốn tình huống khiến lỗi này xuất hiện
1. Sai lầm về dấu ngoặc
Đây là nguyên nhân phổ biến nhất. Bạn định nghĩa một component rất tốt nhưng sau đó lại cố gắng render nó chỉ bằng tên trong dấu ngoặc nhọn. Nếu không có các dấu ngoặc JSX, React sẽ thấy con trỏ hàm thô thay vì một phần tử.
// ❌ Sai: Bạn đang truyền chính hàm đó
const MyComponent = () => <div>Xin chào Thế giới</div>;
function App() {
return (
<div>
{MyComponent}
</div>
);
}
Cách khắc phục: Bao bọc tên component trong thẻ < />. Điều này thông báo cho React khởi tạo component và render kết quả của nó.
// ✅ Đúng: React hiện đã render phần tử
function App() {
return (
<div>
<MyComponent />
</div>
);
}
2. Thiếu dấu ngoặc đơn
Các hàm bổ trợ (helper functions) rất tuyệt vời để giữ cho JSX của bạn sạch sẽ. Tuy nhiên, nếu bạn tham chiếu tên hàm mà không có dấu ngoặc đơn, bạn không thực sự chạy mã đó. Bạn chỉ đang trỏ vào nó.
// ❌ Sai
function Dashboard() {
const renderHeader = () => <h1>Chào mừng trở lại</h1>;
return (
<div>
{renderHeader}
</div>
);
}
Cách khắc phục: Luôn gọi hàm bằng () để trả về JSX bên trong.
// ✅ Đúng
return (
<div>
{renderHeader()}
</div>
);
3. Bẫy đặt tên Prop
Khi bạn truyền một component dưới dạng prop, quy ước đặt tên của React trở nên cực kỳ quan trọng. Nếu prop của bạn bắt đầu bằng chữ cái thường, React sẽ coi nó như một thẻ HTML tiêu chuẩn (như <div>) thay vì một component tùy chỉnh.
// ❌ Sai: 'content' được coi là một biến thông thường
const Layout = ({ content }) => {
return <div>{content}</div>;
};
<Layout content={MyProfilePage} />
Cách khắc phục: Viết hoa chữ cái đầu của tên prop. Thay đổi đơn giản này báo hiệu cho React rằng nó nên xử lý giá trị đó như một component có thể render.
// ✅ Đúng: 'Content' được công nhận là một component
const Layout = ({ Content }) => {
return (
<div>
<Content />
</div>
);
};
<Layout Content={MyProfilePage} />
4. Logic trả về một hàm
Logic điều kiện phức tạp hoặc các hàm bậc cao (higher-order functions) đôi khi có thể trả về một hàm do nhầm lẫn. Điều này thường xảy ra khi bạn sử dụng hàm mũi tên (arrow function) bên trong toán tử ba ngôi không đúng cách.
// ❌ Sai: Nhánh true trả về một hàm, không phải JSX
const status = (isAdmin) => {
return isAdmin ? () => <span>Admin</span> : <span>Người dùng</span>;
};
Trong trường hợp này, nếu isAdmin là true, React sẽ nhận được () => <span>...</span>. Nó không biết phải làm gì với khối logic đó.
Cách gỡ lỗi như một chuyên gia
Nếu lỗi không rõ ràng, đừng hoảng sợ. Hãy sử dụng ba bước sau để tìm ra vấn đề:
- Kiểm tra kỹ Stack Trace: Console của trình duyệt thường làm nổi bật chính xác dòng mã bị lỗi render. Hãy bắt đầu từ đó.
- Kiểm tra kiểu dữ liệu (Typeof): Bao bọc biến nghi ngờ trong
console.log(typeof variable). Nếu console in ra "function", bạn đã tìm thấy lỗi. - React DevTools: Kiểm tra cây component. Nếu bạn thấy một nút trông giống như chữ ký của hàm thay vì một cái tên, đó chính là nguyên nhân.
Những điểm chính cần nhớ
- JSX chỉ là cú pháp rút gọn: Mỗi
<MyComponent />thực chất làReact.createElement(MyComponent). Việc truyền{MyComponent}chỉ đơn thuần là đặt một tham chiếu hàm vào giữa giao diện người dùng của bạn. - Quy tắc viết hoa là quan trọng nhất: Luôn bắt đầu tên component của bạn bằng chữ cái viết hoa. React sử dụng điều này để phân biệt giữa các thẻ HTML có sẵn và logic tùy chỉnh của bạn.
- Phần tử so với Bản thiết kế: Một hàm chỉ là một bản thiết kế. React cần ngôi nhà đã hoàn thiện (phần tử) để hiển thị bất cứ thứ gì lên màn hình.

