React.Component là lớp cơ sở để tạo component sử dụng kế thừa trong React. Trước khi hook được giới thiệu ở phiên bản 16.8, component lớp là cách duy nhất để quản lý trạng thái và vòng đời. Theo React, 2024, component lớp vẫn được hỗ trợ, mặc dù component hàm với hook được khuyến nghị cho các dự án mới.
Những điểm chính
React.Component là một lớp trừu tượng cung cấp các phương thức tích hợp để làm việc với trạng thái, props và vòng đời component. Để tạo một component lớp, bạn cần định nghĩa một lớp mở rộng React.Component và triển khai phương thức render.
React.Component xuất hiện trong phiên bản đầu tiên của React (2013) và vẫn là cách chính để tạo component trong suốt năm năm. Hệ sinh thái React được xây dựng xung quanh các lớp: higher-order component (HOC), render props, context — tất cả các mẫu này đều được triển khai bằng cú pháp lớp.
Với việc phát hành React 16.8 vào năm 2019, nhóm React đã giới thiệu hook như một giải pháp thay thế cho các lớp. Hook giải quyết các vấn đề tương tự — trạng thái, hiệu ứng, context — nhưng không cần kế thừa và ràng buộc ngữ cảnh phức tạp. React.Component vẫn được hỗ trợ đầy đủ, nhưng cách tiếp cận hàm được khuyến nghị cho các dự án mới.
Component lớp tối thiểu là một lớp với một phương thức render duy nhất trả về một phần tử React. render là phương thức bắt buộc duy nhất. Nó phải là một hàm thuần túy của this.props và this.state: cùng một tập hợp props và trạng thái tạo ra cùng một kết quả.
import React, { Component } from 'react';
class Welcome extends Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
Hàm tạo thực thi trước khi mount. Nó gọi super(props) để truyền props cho lớp cha và khởi tạo this.state. Sử dụng hàm tạo cho các mục đích khác — đăng ký, gọi API — không được khuyến nghị; componentDidMount tồn tại cho việc đó.
class Counter extends Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
render() {
return <p>Count: {this.state.count}</p>;
}
}
this.state là một đối tượng chứa dữ liệu của component. Thay đổi trực tiếp nó (this.state.count = 1) bị cấm — nó không kích hoạt render lại và phá vỡ tính dự đoán. Trạng thái phải được cập nhật qua this.setState, tạo ra một đối tượng trạng thái mới và kích hoạt render lại.
setState có thể chấp nhận một đối tượng hoặc một hàm. Dạng hàm được ưu tiên khi trạng thái mới phụ thuộc vào trạng thái trước đó: this.setState(prev => ({ count: prev.count + 1 })). React có thể nhóm nhiều lệnh gọi setState thành một lô duy nhất để tối ưu hiệu suất.
class Toggle extends Component {
constructor(props) {
super(props);
this.state = { isOn: false };
}
handleClick() {
this.setState(prev => ({ isOn: !prev.isOn }));
}
render() {
return (
<button onClick={() => this.handleClick()}>
{this.state.isOn ? 'ON' : 'OFF'}
</button>
);
}
}
Một thuộc tính quan trọng của setState là nó bất đồng bộ. Sau khi gọi setState, trạng thái không được cập nhật ngay lập tức. Nếu bạn cần thực hiện hành động sau khi cập nhật, hãy truyền một callback làm đối số thứ hai: this.setState(newState, () => console.log(this.state)).
Component lớp có các phương thức được định nghĩa sẵn mà React gọi tại các thời điểm cụ thể. Mount — constructor → render → componentDidMount. Cập nhật — render → componentDidUpdate. Hủy mount — componentWillUnmount.
| Phương thức | Giai đoạn | Mục đích |
|---|---|---|
| constructor | Mount | Khởi tạo trạng thái và ràng buộc phương thức |
| render | Mỗi lần | Trả về phần tử React (bắt buộc) |
| componentDidMount | Sau khi mount | Yêu cầu API, đăng ký, bộ định thời |
| componentDidUpdate | Sau cập nhật | Phản ứng với thay đổi props/trạng thái |
| componentWillUnmount | Trước khi xóa | Dọn dẹp đăng ký, bộ định thời, trình lắng nghe sự kiện |
componentDidMount là nơi chính cho các tác dụng phụ sau lần render đầu tiên. Tại đây bạn thực hiện các yêu cầu HTTP, thiết lập kết nối WebSocket và khởi động bộ định thời. Nếu bạn không dọn dẹp đăng ký trong componentWillUnmount, rò rỉ bộ nhớ sẽ xảy ra.
class UserProfile extends Component {
componentDidMount() {
fetch(`/api/users/${this.props.userId}`)
.then(res => res.json())
.then(data => this.setState({ user: data }));
}
componentWillUnmount() {
// Cancel request on unmount
}
render() {
return <div>{this.state.user?.name}</div>;
}
}
Trong JavaScript, phương thức lớp không được ràng buộc với thể hiện theo mặc định. Nếu bạn truyền một phương thức làm callback — cho trình xử lý sự kiện, cho bộ định thời — this sẽ là undefined (trong chế độ nghiêm ngặt) hoặc window (không có chế độ nghiêm ngặt). Nếu không ràng buộc, this.setState sẽ ném lỗi.
Có ba cách để ràng buộc: bind trong hàm tạo, arrow function trong callback và class field với arrow function. Cách đầu tiên là khuyến nghị chính thức của React: ràng buộc một lần trong hàm tạo, không tạo lại hàm mỗi lần render.
// Method 1: bind in constructor (recommended)
class MyComponent extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({ clicked: true });
}
render() {
return <button onClick={this.handleClick}>Click</button>;
}
}
Class fields — cú pháp hiện đại với ràng buộc tự động. Arrow function trong thuộc tính lớp captures this từ phạm vi của hàm tạo. Nhược điểm là phương thức được tạo trên mỗi thể hiện, không phải trên nguyên mẫu, làm tăng bộ nhớ sử dụng cho hàng trăm component cùng loại.
Sự lựa chọn giữa lớp và hàm không chỉ là vấn đề cú pháp. Component hàm với hook giải quyết các vấn đề cố hữu của lớp: trùng lặp logic trong các phương thức vòng đời khác nhau (componentDidMount + componentDidUpdate), phức tạp với this và không thể trích xuất logic liên quan vào một khối tái sử dụng.
Component hàm dễ kiểm tra hơn — chúng không có trạng thái nội bộ (mà trước hook chỉ có trong lớp) và không yêu cầu mount vào DOM để xác minh callback. React khuyến nghị component hàm cho tất cả các dự án mới; tài liệu và ví dụ được viết bằng chúng.
Component lớp vẫn là lựa chọn tốt nhất khi làm việc với mã kế thừa. Nếu một dự án được bắt đầu trước năm 2019, nó có thể chứa hàng ngàn component lớp. Viết lại tất cả chúng thành hook trong một sprint là rủi ro. React đảm bảo tương thích ngược: component lớp sẽ không bị loại bỏ.
Việc di chuyển dần dần bắt đầu bằng việc phân tích component. Component đơn giản không trạng thái được chuyển đổi trước — chúng dễ dàng được thay thế bằng hàm. Tiếp theo — component có một hoặc hai trường trạng thái, nơi useState thay thế trực tiếp this.state và this.setState.
Component phức tạp với nhiều phương thức vòng đời được chuyển đổi bằng useEffect. Logic từ componentDidMount + componentDidUpdate được chia thành các lệnh gọi useEffect riêng biệt với các phụ thuộc khác nhau. componentWillUnmount được thay thế bằng hàm return trong useEffect. Cho logic trạng thái phức tạp, hãy sử dụng useReducer.
Các công cụ di chuyển tự động — @phenomnomnominal/ts-react-class-to-hook hoặc script codemod — có thể tự động chuyển đổi các lớp đơn giản. Cho các trường hợp phức tạp, việc di chuyển vẫn là công việc thủ công đòi hỏi hiểu logic của component nguồn.
Câu hỏi thường gặp
Có. super(props) truyền props cho React.Component cha. Nếu không có lời gọi này, this.props sẽ là undefined bên trong hàm tạo. Trong render và các phương thức vòng đời, props có sẵn ngay cả khi không có super, nhưng đây là hành vi phụ của việc triển khai.
React nhóm nhiều lệnh gọi setState thành một lô duy nhất để giảm số lần render lại không cần thiết. Nếu setState đồng bộ, mỗi lần gọi sẽ kích hoạt render ngay lập tức, giảm hiệu suất trong các cập nhật hàng loạt.
Không. Hook chỉ hoạt động trong component hàm. Đối với các dự án có component lớp, tất cả các mẫu cũ đều có sẵn: render props, HOC và Consumer cho context. Di chuyển sang hook yêu cầu chuyển đổi lớp thành hàm.
React.PureComponent triển khai shouldComponentUpdate với so sánh nông của props và trạng thái. Không giống như Component luôn render lại với setState, PureComponent bỏ qua render lại nếu dữ liệu không thay đổi. Đây là tối ưu hóa cho component không có lồng ghép phức tạp.
Sử dụng componentDidCatch và getDerivedStateFromError. componentDidCatch(error, info) ghi lại lỗi. getDerivedStateFromError cập nhật trạng thái để hiển thị giao diện dự phòng. Các phương thức này chỉ hoạt động trong component lớp — hàm cần một component ErrorBoundary bao bọc.
Tóm tắ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