ReactJS - Chu kỳ sống của Component

Xin chào các bạnfuture开发者! Hôm nay, chúng ta sẽ bắt đầu một hành trình thú vị qua chu kỳ sống của các component React. Đừng lo lắng nếu bạn mới bắt đầu học lập trình - tôi sẽ là người hướng dẫn thân thiện của bạn, giải thích mọi thứ từng bước. Cuối bài hướng dẫn này, bạn sẽ có một sự hiểu biết vững chắc về cách các component React được sinh ra, phát triển và cuối cùng là chia tay. Hãy cùng nhau khám phá!

ReactJS - Component Life Cycle

什么是组件生命周期?

Trước khi chúng ta nhảy vào mã, hãy nói về điều chúng ta.mean bằng "chu kỳ sống". Tương tự như chúng ta con người trải qua các giai đoạn khác nhau trong cuộc sống (sinh ra, phát triển và, à, bạn biết đấy...), các component React cũng có các giai đoạn sống của riêng chúng. Các giai đoạn này được gọi là chu kỳ sống của component.

Hãy tưởng tượng một component React như một vật nuôi ảo. Khi bạn lần đầu tiên tạo ra nó, nó được sinh ra. Sau đó, nó phát triển và thay đổi khi bạn tương tác với nó. Cuối cùng, khi bạn không cần nó nữa, nó sẽ biến mất. Hiểu được chu kỳ sống này rất quan trọng để tạo ra các ứng dụng React linh hoạt và hiệu quả.

Ba giai đoạn chính của cuộc sống của một component

Các component React trải qua ba giai đoạn chính:

  1. Mounting (Sinh ra)
  2. Updating (Phát triển)
  3. Unmounting (Chia tay)

Hãy cùng khám phá từng giai đoạn này và các phương thức liên quan đến chúng.

1. Giai đoạn Mounting

Đây là khi component của chúng ta được sinh ra và thêm vào DOM (Document Object Model - hãy tưởng tượng nó như gia đình cây cối của trang web của bạn).

Các phương thức chính trong giai đoạn này:

Phương thức Mô tả
constructor() Phương thức constructor của component, được gọi trước khi nó được gắn
render() Phương thức thực sự render component
componentDidMount() Được gọi sau khi component được gắn vào DOM

Hãy xem một ví dụ đơn giản:

import React, { Component } from 'react';

class BabyComponent extends Component {
constructor(props) {
super(props);
this.state = { message: "Tôi vừa mới sinh ra!" };
console.log("Constructor: Xin chào, tôi đang được tạo ra!");
}

componentDidMount() {
console.log("componentDidMount: Tôi bây giờ đã có mặt trong DOM!");
}

render() {
console.log("Render: Tôi đang được render!");
return <h1>{this.state.message}</h1>;
}
}

export default BabyComponent;

Trong ví dụ này, BabyComponent của chúng ta trải qua giai đoạn sinh ra. constructor được gọi đầu tiên, thiết lập trạng thái ban đầu. Sau đó render được gọi để tạo ra các phần tử DOM thực tế. Cuối cùng, componentDidMount được gọi, báo hiệu rằng component của chúng ta đã hoàn toàn sinh ra và được thêm vào DOM.

2. Giai đoạn Updating

Giai đoạn này xảy ra khi trạng thái của một component thay đổi hoặc nó nhận được các props mới.

Các phương thức chính trong giai đoạn này:

Phương thức Mô tả
shouldComponentUpdate() Quyết định xem component có nên re-render hay không
render() Re-render component với dữ liệu được cập nhật
componentDidUpdate() Được gọi sau khi component cập nhật

Hãy mở rộng ví dụ trước:

import React, { Component } from 'react';

class GrowingComponent extends Component {
constructor(props) {
super(props);
this.state = { age: 0 };
}

componentDidMount() {
this.ageInterval = setInterval(() => {
this.setState(prevState => ({ age: prevState.age + 1 }));
}, 1000);
}

shouldComponentUpdate(nextProps, nextState) {
return nextState.age % 5 === 0; // Chỉ cập nhật mỗi 5 năm
}

componentDidUpdate() {
console.log(`Tôi vừa tròn ${this.state.age} tuổi!`);
}

render() {
return <h1>Tôi đã ${this.state.age} tuổi</h1>;
}

componentWillUnmount() {
clearInterval(this.ageInterval);
}
}

export default GrowingComponent;

Trong ví dụ này, GrowingComponent "lớn lên" mỗi giây. shouldComponentUpdate đảm bảo chúng ta chỉ tổ chức sinh nhật mỗi 5 năm (để tiết kiệm bánh, bạn biết đấy). Khi component cập nhật, componentDidUpdate ghi một thông báo sinh nhật.

3. Giai đoạn Unmounting

Đây là giai đoạn chia tay, khi một component bị xóa khỏi DOM.

Phương thức chính trong giai đoạn này:

Phương thức Mô tả
componentWillUnmount() Được gọi ngay trước khi component bị gỡ bỏ và hủy

Trong ví dụ GrowingComponent ở trên, chúng ta đã sử dụng componentWillUnmount để xóa interval mà chúng ta đã thiết lập, ngăn chặn bất kỳ rò rỉ bộ nhớ nào.

Ví dụ làm việc của API Chu kỳ sống

Bây giờ, hãy kết hợp tất cả lại trong một ví dụ phức tạp hơn. Chúng ta sẽ tạo một ứng dụng đơn giản "Tracker Cảm xúc" để minh họa tất cả các phương thức chu kỳ sống.

import React, { Component } from 'react';

class MoodTracker extends Component {
constructor(props) {
super(props);
this.state = { mood: 'neutral', intensity: 5 };
console.log('Constructor: Tracker Cảm xúc đang được tạo ra');
}

componentDidMount() {
console.log('ComponentDidMount: Tracker Cảm xúc bây giờ đã có mặt trong DOM');
this.moodInterval = setInterval(() => {
const moods = ['happy', 'sad', 'excited', 'nervous', 'neutral'];
const newMood = moods[Math.floor(Math.random() * moods.length)];
this.setState({ mood: newMood });
}, 5000);
}

shouldComponentUpdate(nextProps, nextState) {
return this.state.mood !== nextState.mood;
}

componentDidUpdate() {
console.log(`Cảm xúc được cập nhật: ${this.state.mood}`);
}

componentWillUnmount() {
console.log('ComponentWillUnmount: Tạm biệt Tracker Cảm xúc!');
clearInterval(this.moodInterval);
}

handleIntensityChange = (e) => {
this.setState({ intensity: e.target.value });
}

render() {
console.log('Render: Tracker Cảm xúc đang render');
return (
<div>
<h1>Tình trạng cảm xúc hiện tại: {this.state.mood}</h1>
<input
type="range"
min="1"
max="10"
value={this.state.intensity}
onChange={this.handleIntensityChange}
/>
<p>Mức độ: {this.state.intensity}</p>
</div>
);
}
}

export default MoodTracker;

Component MoodTracker này minh họa tất cả các phương thức chu kỳ sống chúng ta đã thảo luận. Nó thay đổi cảm xúc ngẫu nhiên mỗi 5 giây và cho phép người dùng điều chỉnh mức độ cảm xúc.

API Chu kỳ sống trong Ứng dụng Quản lý Chi tiêu

Bây giờ, hãy xem chúng ta có thể sử dụng các phương thức chu kỳ sống này trong một ứng dụng thực tế như Ứng dụng Quản lý Chi tiêu.

import React, { Component } from 'react';

class ExpenseManager extends Component {
constructor(props) {
super(props);
this.state = { expenses: [], total: 0 };
}

componentDidMount() {
// Simulate fetching expenses from an API
setTimeout(() => {
const fetchedExpenses = [
{ id: 1, description: 'Supermarket', amount: 50 },
{ id: 2, description: 'Gas', amount: 30 },
{ id: 3, description: 'Movie tickets', amount: 20 },
];
this.setState({ expenses: fetchedExpenses }, this.calculateTotal);
}, 1000);
}

shouldComponentUpdate(nextProps, nextState) {
// Only update if the total has changed
return this.state.total !== nextState.total;
}

componentDidUpdate() {
console.log(`Total expenses updated: $${this.state.total}`);
}

calculateTotal = () => {
const total = this.state.expenses.reduce((sum, expense) => sum + expense.amount, 0);
this.setState({ total });
}

render() {
return (
<div>
<h1>Expense Manager</h1>
<ul>
{this.state.expenses.map(expense => (
<li key={expense.id}>{expense.description}: ${expense.amount}</li>
))}
</ul>
<h2>Total: ${this.state.total}</h2>
</div>
);
}
}

export default ExpenseManager;

Trong component ExpenseManager này:

  1. Chúng ta sử dụng componentDidMount để simulate việc lấy dữ liệu chi tiêu từ API khi component lần đầu tiên được tải.
  2. shouldComponentUpdate đảm bảo chúng ta chỉ re-render khi tổng chi tiêu thay đổi, không phải cho mỗi cập nhật nhỏ.
  3. componentDidUpdate ghi thông báo mới khi tổng chi tiêu thay đổi.

Bằng cách sử dụng các phương thức chu kỳ sống này, chúng ta tạo ra một ứng dụng theo dõi chi tiêu hiệu quả và phản hồi tốt.

Hiểu được chu kỳ sống của component rất quan trọng để xây dựng các ứng dụng React hiệu quả. Nó cho phép bạn kiểm soát khi nào các hành động xảy ra, tối ưu hóa hiệu suất và quản lý tài nguyên một cách hiệu quả. Hãy tiếp tục thực hành với các khái niệm này, và sớm bạn sẽ tạo ra các ứng dụng React phức tạp và linh hoạt một cách dễ dàng!

Credits: Image by storyset