Functional Component — là cách tạo component React bằng các hàm JavaScript thông thường, đã trở thành tiêu chuẩn sau khi React 16.8 ra mắt và hooks xuất hiện. Functional component nhận props và trả về các phần tử React mà không yêu cầu kế thừa từ React.Component. Theo React, 2024, 97% component mới trong hệ sinh thái React được viết dưới dạng hàm.
Những Điểm Chính
Functional Component là một component React được định nghĩa như một hàm nhận đối tượng props và trả về một phần tử React. Trước React 16.8, các component này được gọi là stateless vì chúng không thể quản lý trạng thái nội bộ.
Với sự ra đời của hooks trong React 16.8 (tháng 2 năm 2019), functional component đã có quyền truy cập vào state (useState), hiệu ứng phụ (useEffect), ngữ cảnh (useContext) và ref (useRef). Thuật ngữ “stateless” đã lỗi thời — functional component hiện đại quản lý state một cách đầy đủ.
React chính thức khuyến nghị functional component là cách chính để tạo component. Tất cả tài liệu trên react.dev, ví dụ, hướng dẫn và API mới (Server Components, Actions) đều được xây dựng trên phương pháp hàm. Class component không bị loại bỏ, nhưng các tính năng mới của React chỉ khả dụng thông qua hooks.
Functional component đơn giản nhất là một hàm trả về JSX. Nó nhận props làm đối số, không yêu cầu constructor, gọi super hay ràng buộc this. Props có thể truy cập trực tiếp qua đối số của hàm — không cần this.props.
// Functional component without state
function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
}
// Arrow function (common variant)
const Greeting = ({ name }) => (
<h1>Hello, {name}!</h1>
);
Để thêm state, sử dụng useState. Hook trả về một tuple gồm hai giá trị: state hiện tại và hàm setter. Không giống this.setState dựa trên class, useState thay thế hoàn toàn giá trị thay vì hợp nhất với giá trị trước đó.
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
}
Hooks là nền tảng của React hiện đại. Mỗi hook giải quyết một nhiệm vụ cụ thể: useState — state, useEffect — hiệu ứng phụ, useContext — truy cập ngữ cảnh, useRef — tham chiếu phần tử DOM, useCallback và useMemo — memoization.
useEffect thay thế đồng thời componentDidMount, componentDidUpdate và componentWillUnmount. Đối số đầu tiên là callback với hiệu ứng, đối số thứ hai là mảng phụ thuộc. Nếu mảng trống, hiệu ứng chạy một lần sau khi gắn kết. Nếu phụ thuộc được chỉ định, nó chạy khi bất kỳ phụ thuộc nào thay đổi.
import React, { useState, useEffect } from 'react';
function UserData({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
let cancelled = false;
fetch(`/api/users/${userId}`)
.then(res => res.json())
.then(data => {
if (!cancelled) setUser(data);
});
// Cleanup - analog of componentWillUnmount
return () => { cancelled = true; };
}, [userId]); // Dependency
return <div>{user?.name}</div>;
}
Ưu điểm chính của functional component là tái sử dụng logic thông qua custom hooks. Trong khi ở class component, logic bị trùng lặp giữa componentDidMount và componentDidUpdate, thì trong functional component, nó được trích xuất thành một hàm riêng với tiền tố use. Custom hooks là giải pháp thay thế chính cho HOC và render props.
React khuyến nghị kết hợp thay vì kế thừa để tái sử dụng code giữa các component. Functional component lý tưởng cho việc kết hợp: một component có thể chứa nhiều component khác, truyền props và children cho chúng.
Mẫu children — khi một component nhận các phần tử con qua prop children — được triển khai tự nhiên: function Layout({ children }). Tương tự slots của Vue được triển khai qua props component có tên: function Page({ header, sidebar, content }).
Kế thừa hiếm khi được sử dụng trong React. Ngay cả class component, về mặt kỹ thuật hỗ trợ extends, hiếm khi tạo thành hệ thống phân cấp sâu hơn một cấp. Functional component với kết hợp hoàn toàn đáp ứng nhu cầu tái sử dụng code mà không cần kế thừa.
Functional component đi kèm với cơ chế tối ưu hóa tích hợp. React.memo — tương đương PureComponent cho hàm: ngăn chặn việc kết xuất lại nếu props không thay đổi (so sánh nông). useMemo lưu trữ kết quả tính toán giữa các lần kết xuất.
import React, { useMemo } from 'react';
// React.memo - memoize component
const ExpensiveList = React.memo(({ items }) => {
return <ul>
{items.map(item =>
<li key={item.id}>{item.name}</li>
)}
</ul>;
});
// useMemo - caching result
function Dashboard({ transactions }) {
const summary = useMemo(() => {
return transactions.reduce((acc, t) => acc + t.amount, 0);
}, [transactions]);
return <p>Total: {summary}</p>;
}
useCallback ghi nhớ các hàm callback để chúng không bị tạo lại mỗi lần kết xuất. Điều này rất quan trọng khi truyền hàm cho component con được bọc trong React.memo: nếu không có useCallback, component con sẽ kết xuất lại mỗi lần vì tham chiếu hàm thay đổi.
Sự khác biệt giữa các phương pháp vượt ra ngoài cú pháp. Functional component là closure: state và hiệu ứng được gắn với một lần kết xuất cụ thể. Class component sử dụng this: state luôn được lấy từ this.state, có thể đã lỗi thời khi callback bất đồng bộ thực thi.
| Khía cạnh | Functional | Class |
|---|---|---|
| State | useState (riêng biệt) | this.state + this.setState |
| Hiệu ứng | useEffect với phụ thuộc | componentDidMount + componentDidUpdate |
| Ngữ cảnh | useContext | Context.Consumer hoặc static contextType |
| Tối ưu hóa | React.memo + useMemo | PureComponent + shouldComponentUpdate |
| Tái sử dụng logic | Custom hooks | HOC / Render props |
| this | Không có | bind trong constructor |
Functional component cung cấp luồng thực thi tuyến tính. Trong class component, logic liên quan thường bị phân tán trên nhiều phương thức vòng đời. Ví dụ, đăng ký WebSocket được thiết lập trong componentDidMount và hủy bỏ trong componentWillUnmount. Trong functional component, cả hai thao tác đều nằm trong một useEffect duy nhất với hàm dọn dẹp trả về.
TypeScript hoạt động tự nhiên hơn với functional component so với class. Định kiểu props — một interface cho đối số hàm. Kiểu trả về là JSX.Element hoặc ReactNode. useState tự động suy luận kiểu từ giá trị khởi tạo.
import React, { useState } from 'react';
interface ButtonProps {
label: string;
variant?: 'primary' | 'secondary';
onClick: () => void;
}
const Button: React.FC<ButtonProps> =
({ label, variant = 'primary', onClick }) => (
<button
className={`btn btn-${variant}`}
onClick={onClick}
>
{label}
</button>
);
TypeScript hiện đại cho phép định kiểu useReducer với kiểu union phân biệt, Generics trong custom hooks và xác thực children nghiêm ngặt qua React.PropsWithChildren. Functional component với TypeScript cung cấp an toàn kiểu đầy đủ mà không cần trừu tượng bổ sung.
Câu hỏi Thường gặp
Functional component đơn giản hơn: không có constructor, bind, this hay các phương thức vòng đời phân tán. Hooks cho phép nhóm logic liên quan. React đầu tư nguồn lực vào phát triển hooks, không phải class. Server Components và các tính năng mới chỉ khả dụng trong hàm.
Có, thông qua useEffect với bộ đếm thời gian bên trong và hàm dọn dẹp cho clearInterval. Hãy chú ý đến closure: nếu bạn đang tăng bộ đếm, hãy sử dụng dạng hàm của setState: setCount(c => c + 1) để không phụ thuộc vào giá trị cũ trong closure.
Sử dụng useRef để lưu trữ giá trị trước đó. Cập nhật ref trong useEffect sau mỗi lần kết xuất. Custom hook usePrevious giúp so sánh sạch sẽ: const prev = usePrevious(value);
React.memo là HOC để ghi nhớ toàn bộ component: ngăn kết xuất lại nếu props không thay đổi. useMemo là hook để ghi nhớ một giá trị cụ thể bên trong component: lưu trữ kết quả hàm giữa các lần kết xuất theo mảng phụ thuộc.
Cách đơn giản nhất là useState với khởi tạo từ props + useEffect với phụ thuộc vào props để đồng bộ hóa. Cho các trường hợp hiếm, React khuyến nghị sử dụng key để buộc tạo lại component khi dữ liệu đầu vào thay đổi.
Tổng kết
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm