Một component React là một hàm JavaScript trả về JSX: một phần giao diện dùng lại được, như một nút bấm, một thẻ card hay cả một trang. Bạn dùng nó giống một thẻ HTML, <Profile />, và React gọi hàm đó để biết cần đưa gì lên màn hình. Ứng dụng được xây dựng bằng cách đặt component bên trong các component khác.
App render Profile hai lần, và mỗi Profile render một Avatar. Đổi chữ viết tắt bên trong Avatar, cả hai hồ sơ đều cập nhật, vì chúng dùng chung một định nghĩa. Hiện tại mọi người trong danh sách này đều giống nhau; trang tiếp theo, props, chỉ cách truyền cho mỗi bản sao dữ liệu riêng.
Viết một component
Một function component có hai yêu cầu:
- Tên của nó bắt đầu bằng chữ in hoa:
Profile, không phảiprofile. - Nó trả về thứ React có thể render: JSX, một chuỗi, một số,
null(không render gì) hoặc một mảng các giá trị đó.
function Welcome() {
return <h1>Welcome back</h1>;
}
// Arrow functions work the same way
const Welcome = () => <h1>Welcome back</h1>;
Khi JSX trải dài nhiều dòng, hãy bọc nó trong cặp ngoặc tròn sau return. Thiếu ngoặc, một lệnh return theo sau là dấu xuống dòng sẽ trả về undefined, và mọi thứ sau đó bị bỏ qua.
Vì sao tên phải viết hoa
JSX nhìn vào chữ cái đầu tiên của thẻ. Chữ thường nghĩa là một phần tử HTML có sẵn, nên <div> vẫn là <div>. Chữ hoa nghĩa là "một biến trong phạm vi", nên <Profile /> gọi hàm Profile của bạn. Đặt tên component bằng chữ thường, React sẽ tạo ra một phần tử HTML lạ mang tên đó thay vào:
Dòng thứ hai chỉ hiển thị nhãn của nó, và console chỉ hiện Greeting ran. React đã đặt một thẻ <greeting> rỗng vào trang và không bao giờ gọi hàm viết thường. Bản build development còn cảnh báo The tag <greeting> is unrecognized in this browser; phần xem trước chạy như bản build production, nên bạn chỉ thấy phần chữ bị thiếu. Đổi tên hàm thành Greetings và thẻ thành <Greetings /> để sửa lỗi.
Ghép các component
Component được tạo ra để lồng vào nhau. Một trang là một cây: App ở trên cùng, rồi đến các phần bố cục, rồi các phần nhỏ hơn cho tới từng nút bấm. Mỗi component chỉ biết về những phần nó render trực tiếp, nên bạn có thể suy nghĩ về từng component một.
Mỗi LikeButton có state riêng, nên thích một bài viết không ảnh hưởng tới các bài khác. Để thêm nút chia sẻ vào mọi bài viết, bạn viết nó một lần rồi thêm <ShareButton /> vào trong Post.
Khi nào nên tách component
Không có quy tắc cố định, nhưng vài dấu hiệu cho thấy một phần xứng đáng thành component riêng: cùng một đoạn markup xuất hiện ở hai nơi, một phần của JSX có state riêng (như nút thích ở trên), hoặc hàm đã dài tới mức bạn phải cuộn mới thấy return. Tách theo những ranh giới đó giúp mỗi component đủ nhỏ để đọc trong một màn hình. Tách quá sớm cũng chẳng tốn mấy: component chỉ là một hàm, nên gộp hai cái lại với nhau rất dễ.
Export và import component
Các trình soạn thảo ở đây chỉ chứa một tệp, nhưng một dự án thật đặt các component trong tệp riêng. Một tệp có thể có một default export và số lượng named export tùy ý:
// Avatar.jsx
export default function Avatar({ initials }) {
return <div className="avatar">{initials}</div>;
}
// Badge.jsx
export function Badge({ label }) {
return <span className="badge">{label}</span>;
}
export function NewBadge() {
return <Badge label="new" />;
}
// Profile.jsx
import Avatar from './Avatar.jsx';
import { Badge, NewBadge } from './Badge.jsx';
export default function Profile() {
return (
<div>
<Avatar initials="AL" />
<Badge label="admin" />
<NewBadge />
</div>
);
}
Default export có thể được import dưới bất kỳ tên nào; named export được import trong cặp ngoặc nhọn với đúng tên của nó. Các nhóm thường chọn một kiểu và theo nó. Tên tệp thường trùng với component: Avatar.jsx export Avatar.
Giữ component thuần
React mong một component hoạt động như một hàm thuần trong lúc render: cùng props và state thì cho cùng JSX, và việc render không thay đổi thứ gì đã tồn tại trước khi nó chạy. React có thể render một component nhiều lần, vào những lúc bạn không kiểm soát, nên một component sửa biến bên ngoài trong lúc render sẽ cho ra đầu ra khác nhau mỗi lần.
Các cốc không thuần bắt đầu là 1, 2, 3. Bấm nút: không có gì về khách thay đổi, vậy mà danh sách không thuần giờ là 4, 5, 6, vì mỗi lần render lại cộng thêm vào biến dùng chung guest. Các cốc thuần nhận số qua props và vẫn đúng. Ở chế độ development, Strict Mode render mỗi component hai lần để làm lộ đúng loại bug này; phần xem trước chạy như bản build production, nên ở đây sự sai lệch chỉ lộ ra khi bạn render lại.
Thay đổi mọi thứ là được, chỉ là đừng làm trong lúc render. Hãy cập nhật state trong trình xử lý sự kiện, và làm việc với thế giới bên ngoài (timer, subscription, tiêu đề tài liệu) trong effect.
Component và element
Component là hàm, Profile. Một element là thứ JSX tạo ra khi bạn viết <Profile />: một đối tượng nhỏ nói rằng "hãy render Profile với các props này". React tạo element, gọi các component mà chúng nêu tên, rồi biến kết quả thành DOM. Bạn không bao giờ tự gọi component dưới dạng Profile(); bạn viết <Profile /> và để React gọi nó, nhờ đó React theo dõi được state và vị trí của nó trong cây.
Vị trí đó rất quan trọng. Ví dụ này định nghĩa một component bên trong component khác, một lỗi rất hay gặp:
Gõ gì đó, rồi bấm nút: chữ của bạn biến mất. Mỗi lần App render lại tạo ra một hàm NameField hoàn toàn mới, nên React thấy một loại component khác ở vị trí đó và vứt bỏ cái cũ cùng state của nó. Chuyển NameField lên trên App, ở cấp cao nhất của tệp, và chữ sẽ còn nguyên sau mọi lần bấm. Trang về rendering giải thích cách React quyết định giữ lại những gì.
Function component và class component
Trước khi hook xuất hiện trong React 16.8, những component cần state được viết dưới dạng class:
import { Component } from 'react';
class Welcome extends Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
Class component vẫn chạy trong React 19, và bạn sẽ gặp chúng trong các codebase cũ và trong error boundary, thứ vẫn cần một class. Code mới dùng function component với các hook như useState và useEffect, làm được cùng việc với ít code hơn. Trang class component đối chiếu từng tính năng của class với hook tương ứng.
Câu hỏi thường gặp
Component trong React là gì?
Component là một phần giao diện dùng lại được, viết dưới dạng một hàm JavaScript trả về JSX. Bạn dùng nó giống một thẻ HTML, <Profile />, và React gọi hàm đó để biết cần vẽ gì.
Vì sao tên component React phải bắt đầu bằng chữ in hoa?
JSX dựa vào chữ cái đầu để quyết định một thẻ là gì. Thẻ viết thường như <profile /> được xem là một phần tử HTML tên profile, và hàm của bạn không bao giờ được gọi. Thẻ viết hoa như <Profile /> mới trỏ tới component của bạn.
Function component và class component khác nhau thế nào?
Cả hai đều mô tả giao diện. Function component là hàm thông thường và dùng hook cho state và effect; class component kế thừa React.Component và dùng các phương thức như render và componentDidMount. Code mới dùng function component.
Component thuần (pure) trong React là gì?
Component thuần trả về cùng một JSX với cùng props và state, và không thay đổi gì bên ngoài nó trong lúc render. React dựa vào điều này để render component bao nhiêu lần tùy cần mà không gây bất ngờ.
Có thể định nghĩa một component bên trong component khác không?
Nên tránh. Component định nghĩa bên trong một component khác là một hàm mới sau mỗi lần render, nên React coi nó là component khác ở mỗi lần và đặt lại state của nó. Hãy định nghĩa component ở cấp cao nhất của tệp.