Vòng Đời Component trong ReactJS: Từ Khởi Tạo Đến Hủy Bỏ

Vòng đời của một component trong ReactJS là một khái niệm quan trọng mà mọi nhà phát triển React cần nắm vững. Nó cho phép chúng ta kiểm soát cách component được tạo, cập nhật và hủy bỏ, từ đó tối ưu hóa hiệu suất và quản lý ứng dụng hiệu quả hơn. Bài viết này sẽ đi sâu vào từng giai đoạn của vòng đời component, kèm theo ví dụ minh họa chi tiết, giúp bạn hiểu rõ và áp dụng vào thực tế.

Sơ đồ vòng đời component ReactJSSơ đồ vòng đời component ReactJS

1. Khởi Tạo (Initialization)

Đây là giai đoạn đầu tiên khi một component được tạo ra. Hàm constructor() được gọi để khởi tạo các giá trị ban đầu của component, bao gồm state và các props được truyền vào.

Ví dụ:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
    console.log('Component được khởi tạo');
  }
  // ...
}

Trong ví dụ này, chúng ta khởi tạo state với một thuộc tính count có giá trị ban đầu là 0.

2. Gắn Kết (Mounting)

Giai đoạn gắn kết là quá trình component được thêm vào DOM (Document Object Model) của trình duyệt. Giai đoạn này bao gồm các phương thức sau:

2.1. componentWillMount() (Không Khuyến Khích)

Phương thức này được gọi ngay trước khi component được render lần đầu tiên. Tuy nhiên, từ React 16.3, phương thức này không được khuyến khích sử dụng và sẽ bị loại bỏ trong các phiên bản tương lai. Lý do là vì nó có thể gây ra các vấn đề không mong muốn khi render phía server (server-side rendering).

2.2. render()

Đây là phương thức quan trọng nhất của một component. Nó trả về một mô tả về những gì component sẽ hiển thị trên màn hình. Mô tả này có thể là một React element, một mảng các React element, hoặc null (nếu không muốn render gì cả).

Ví dụ:

render() {
  console.log('Component đang render');
  return (
    <div>
      <h1>Chào mừng!</h1>
      <p>Số lượng: {this.state.count}</p>
    </div>
  );
}

2.3. componentDidMount()

Phương thức này được gọi ngay sau khi component đã được render và thêm vào DOM. Đây là nơi thích hợp để thực hiện các tác vụ như gọi API, thiết lập các listener sự kiện, hoặc tương tác trực tiếp với DOM.

Ví dụ:

componentDidMount() {
  console.log('Component đã được gắn kết vào DOM');
  // Gọi API để lấy dữ liệu
  fetch('/api/data')
    .then(response => response.json())
    .then(data => this.setState({ data: data }));
}

Ví dụ tổng quan về Mounting:

import React, { Component } from 'react';

class App extends Component {
  constructor(props) {
    super(props);
    console.log('constructor');
  }

  componentWillMount() {
    console.log('componentWillMount');
  }

  componentDidMount() {
    console.log('componentDidMount');
  }

  render() {
    console.log('render');
    return (
      <div>
        <h1>Vòng Đời Component</h1>
      </div>
    );
  }
}

export default App;

Khi component này được render, thứ tự các hàm được gọi sẽ là: constructor -> componentWillMount -> render -> componentDidMount.

Kết quả console.log khi component mountingKết quả console.log khi component mounting

3. Cập Nhật (Updating)

Giai đoạn cập nhật xảy ra khi component nhận được props mới hoặc state thay đổi. Giai đoạn này bao gồm các phương thức sau:

3.1. componentWillReceiveProps(nextProps) (Không Khuyến Khích)

Phương thức này được gọi khi component nhận được props mới. Tương tự như componentWillMount(), phương thức này cũng không được khuyến khích sử dụng từ React 16.3.

3.2. shouldComponentUpdate(nextProps, nextState)

Phương thức này cho phép bạn kiểm soát việc component có nên được render lại hay không. Nó nhận vào nextPropsnextState là các giá trị props và state mới. Nếu phương thức này trả về true, component sẽ được render lại. Nếu trả về false, component sẽ bỏ qua quá trình render. Mặc định, phương thức này trả về true.

Ví dụ:

shouldComponentUpdate(nextProps, nextState) {
  // Chỉ render lại nếu giá trị count thay đổi
  return nextState.count !== this.state.count;
}

3.3. componentWillUpdate(nextProps, nextState) (Không Khuyến Khích)

Phương thức này được gọi ngay trước khi component được render lại. Tương tự như componentWillMount()componentWillReceiveProps(), phương thức này cũng không được khuyến khích sử dụng từ React 16.3.

3.4. render()

Phương thức này được gọi lại để render component với các giá trị props và state mới.

3.5. componentDidUpdate(prevProps, prevState)

Phương thức này được gọi ngay sau khi component đã được render lại và cập nhật DOM.

Ví dụ về cập nhật state:

import React, { Component } from 'react';

class App extends Component {
  constructor(props) {
    super(props);
    console.log('constructor');
    this.state = {
      component: 'Component Init'
    };
  }

  updateState = () => {
    this.setState({ component: 'New State' });
  }

  shouldComponentUpdate(nextProps, nextState) {
    console.log('shouldComponentUpdate ' + this.state.component);
    return true;
  }

  componentWillUpdate(nextProps, nextState) {
    console.log('componentWillUpdate ' + this.state.component);
  }

  componentDidUpdate(prevProps, prevState) {
    console.log('componentDidUpdate ' + this.state.component);
  }

  render() {
    console.log('render');
    console.log(this.state.component);
    return (
      <div>
        <h1>{this.state.component}</h1>
        <button onClick={this.updateState}>Click Me</button>
      </div>
    );
  }
}

export default App;

Khi nút “Click Me” được nhấn, thứ tự các hàm được gọi sẽ là: shouldComponentUpdate -> componentWillUpdate -> render -> componentDidUpdate.

Kết quả console.log khi component update stateKết quả console.log khi component update state

Ví dụ về cập nhật props:

Để minh họa, chúng ta có hai component: AppContent. Component App chứa state fullName và truyền nó xuống component Content thông qua props name.

// App.js
import React, { Component } from 'react';
import Content from './Content';

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      fullName: 'Tí'
    };
  }

  updateState = () => {
    this.setState({ fullName: 'Tèo Văn Tí' });
  }

  render() {
    return (
      <div>
        <Content name={this.state.fullName} />
        <button onClick={this.updateState}>Click Me</button>
      </div>
    );
  }
}

export default App;

// Content.js
import React, { Component } from 'react';

class Content extends Component {
  componentWillReceiveProps(nextProps) {
    console.log('componentWillReceiveProps ' + this.props.name);
  }

  shouldComponentUpdate(nextProps, nextState) {
    console.log('shouldComponentUpdate ' + this.props.name);
    return true;
  }

  componentWillUpdate(nextProps, nextState) {
    console.log('componentWillUpdate ' + this.props.name);
  }

  componentDidUpdate(prevProps, prevState) {
    console.log('componentDidUpdate ' + this.props.name);
  }

  render() {
    return (
      <div>
        <p>{this.props.name}</p>
      </div>
    );
  }
}

export default Content;

Khi nút “Click Me” được nhấn, thứ tự các hàm được gọi trong component Content sẽ là: componentWillReceiveProps -> shouldComponentUpdate -> componentWillUpdate -> render -> componentDidUpdate.

Kết quả console.log khi component update propsKết quả console.log khi component update props

4. Hủy Bỏ (Unmounting)

Giai đoạn hủy bỏ xảy ra khi component bị gỡ bỏ khỏi DOM.

4.1. componentWillUnmount()

Phương thức này được gọi ngay trước khi component bị gỡ bỏ khỏi DOM. Đây là nơi thích hợp để thực hiện các tác vụ dọn dẹp, chẳng hạn như hủy bỏ các listener sự kiện, giải phóng tài nguyên, hoặc hủy các timer.

Ví dụ:

componentWillUnmount() {
  console.log('Component sắp bị gỡ bỏ khỏi DOM');
  // Hủy bỏ listener sự kiện
  window.removeEventListener('resize', this.handleResize);
}

Kết Luận

Hiểu rõ vòng đời của component là yếu tố then chốt để xây dựng các ứng dụng React hiệu quả và dễ bảo trì. Việc sử dụng đúng các phương thức vòng đời giúp bạn kiểm soát quá trình render, tối ưu hóa hiệu suất và quản lý tài nguyên một cách hiệu quả. Hy vọng bài viết này đã cung cấp cho bạn cái nhìn tổng quan và chi tiết về vòng đời component trong ReactJS.