openplanning

Các phương thức trong vòng đời của ReactJS Component

  1. Component Lifecycle
  2. UNSAFE_componentWillMount()
  3. componentDidMount()
  4. componentWillReceiveProps (nextProps)
  5. shouldComponentUpdate (nextProps,nextState)
  6. UNSAFE_componentWillUpdate (nextProps,nextState)
  7. componentDidUpdate (prevProps,prevState)

1. Component Lifecycle

Một loạt các thay đổi mà Component trải qua từ khi nó được tạo ra cho tới khi nó kết thúc (bị hủy) được gọi là một vòng đời (lifecycle) của Component. Trong quá trình tồn tại của Component các phương thức sẽ được gọi, dưới đây là hình ảnh minh họa vòng đời của Component và các phương thức sẽ được gọi trong các giai đoạn khác nhau.
Từ phiên bản 16.3, một vài phương thức trong vòng đời của Component đã được đổi tên, nó có thêm tiếp đầu ngữ "UNSAFE_" như một cách để cảnh báo rằng hãy cẩn thận khi bạn viết đè (Override) phương thức này, bởi vì các phương thức này thường hay bị hiểu lầm và bị lạm dụng một cách tinh tế. Nó có thể gây ra các vấn đề với "Async Rendering".

2. UNSAFE_componentWillMount()

Phương thức UNSAFE_componentWillMount được gọi trước khi ReactJS gọi phương thức render() để vẽ (render) Component lên trên giao diện trong lần đầu tiên. Phương thức này có thể thực thi tại cả hai phía ServerClient.
Phương thức UNSAFE_componentWillMount cho bạn một cơ hội để cấu hình, cập nhập trạng thái, tính toán các giá trị, để chuẩn bị cho lần render đầu tiên. Tại thời điểm này stateprops đã được định nghĩa, bạn có thể truy vấn an toàn this.state, this.props và biết chắc chắn các giá trị của chúng.
person.jsx
class Person extends React.Component {
  constructor(props) {
    super(props);
    this.state = { mode: undefined };
  }

  UNSAFE_componentWillMount() {
    let modeValue;
    if (this.props.age > 70) {
      modeValue = "old";
    } else if (this.props.age < 18) {
      modeValue = "young";
    } else {
      modeValue = "middle";
    }
    this.setState({ mode: modeValue });
  }

  render() {
    return (
      <div className={"person person-" + this.state.mode}>
        {this.props.name} (age: {this.props.age})
      </div>
    );
  }
}

Person.defaultProps = { age: "unknown" };

// Render
ReactDOM.render(
  <Person name="Donald Trump" age="72" />,
  document.getElementById("person1")
);
ReactDOM.render(
  <Person name="Ivanka Trump" age="36" />,
  document.getElementById("person2")
);
person.html
<!DOCTYPE html>
<html lang="en">
   <head>
      <meta charset="UTF-8">
      <title>ReactJS UNSAFE_componentWillMount()</title>
      <script src="https://unpkg.com/react@16.4.2/umd/react.production.min.js"></script>
      <script src="https://unpkg.com/react-dom@16.4.2/umd/react-dom.production.min.js"></script>
      <script src="https://unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>
      <style>
         .person  {
         border:1px solid #cbbfab;
         width: 250px;
         height: 50px;
         padding: 5px;
         margin: 5px;
         }
         .person-old {
         background-color: Gray;
         }
         .person-middle {
         background-color: LightGray;
         }
         .person-young {
         background-color: white;
         }
      </style>
   </head>
   <body>
      <h1>UNSAFE_componentWillMount():</h1>

      <div id="person1"></div>
      <div id="person2"></div>

      <script src="person.jsx" type="text/babel"></script>
   </body>
</html>
Chạy ví dụ:

3. componentDidMount()

Phương thức componentDidMount() được gọi ngay sau khi Component được vẽ (render) lên giao diện lần đầu tiên, nó được thực thi tại phía Client.
Phương thức componentDidMount() được gọi khi Component đã được render lên trên giao diện 1 lần, vì vậy trong phương thức này bạn có thể truy cập vào Native UI (DOM, UIView,..) để làm một việc gì đó mà bạn muốn. Bạn cũng có thể gọi đến một thư viện Javascript khác trong phương thức này, chẳng hạn gọi đến thư viện biểu đồ (Chart) để hiển thị biểu đồ theo dữ liệu của Component.
Phương thức componentDidMount() cũng có thể là nơi để bạn sử dụng AJAX lấy dữ liệu từ Server, sau đó gọi setState() để thay đổi trạng thái của Component, nếu thành công Component sẽ được render thêm 1 lần nữa.
Example:
OK, trong ví dụ này tôi mô phỏng việc tải (load) dữ liệu từ Server trong phương thức componentDidMount().
employee.jsx
class Employe extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      loaded: false,
      empId: "[empId]",
      fullName: "[fullName]"
    };
  }

  // Load data from Server..
  loadEmployeeData() {
    setTimeout(() => {
      console.log("Data is loaded");
      this.setState({
        loaded: true,
        empId: this.props.empId,
        fullName: "Emp " + Math.random()
      });
    }, 1000);
  }

  componentDidMount() {
    this.loadEmployeeData();
  }

  render() {
    if (this.state.loaded == true) {
      return (
        <div className="employee">
          <p>Emp Id: {this.state.empId}</p>
          <p>Full Name: {this.state.fullName}</p>
        </div>
      );
    } else {
      return (
        <div className="employee">
          <p>
            Wait while data loading. EmpID: {this.props.empId}
          </p>
        </div>
      );
    }
  }
}

// Render
ReactDOM.render(<Employe empId="1" />, document.getElementById("employee1"));
employee.html
<!DOCTYPE html>
<html lang="en">
   <head>
      <meta charset="UTF-8">
      <title>ReactJS componentDidMount()</title>
      <script src="https://unpkg.com/react@16.4.2/umd/react.production.min.js"></script>
      <script src="https://unpkg.com/react-dom@16.4.2/umd/react-dom.production.min.js"></script>
      <script src="https://unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>

      <style>
         .employee  {
         border:1px solid #cbbfab;
         padding: 5px;
         margin: 5px;
         }
      </style>
   </head>
   <body>
      <h1>componentDidMount():</h1>
      
      <div id="employee1"></div>

      <script src="employee.jsx" type="text/babel"></script>
   </body>
</html>
Chạy tập tin employee.html trên HTTP Server:

4. componentWillReceiveProps (nextProps)

5. shouldComponentUpdate (nextProps,nextState)

Phương thức shouldComponentUpdate() trả về true/false, nó được gọi sau khi Component được thiết lập trạng thái mới thông qua phương thức setState(). Tại shouldComponentUpdate() bạn có thể quyết định nên hay không nên re-render (vẽ lại) Component trên giao diện.
  • Nếu phương thức trả về true thì Component sẽ được re-render (vẽ lại) trên giao diện.
  • Nếu phương thức trả về false, sẽ không có gì được thực hiện tiếp theo.
odd-number.jsx
class NumberView extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      currentNumber: 1
    };
  }

  nextValue() {
    this.setState((prevState, props) => {
      return {
        currentNumber: prevState.currentNumber + 1
      };
    });
  }

  shouldComponentUpdate(nextProps, nextState) {
    // Odd Number
    return nextState.currentNumber % 2 == 1;
  }

  render() {
    return (
      <div className="number-viewer">
        <button onClick={() => this.nextValue()}>Next Value</button>
        <p>Current Value: {this.state.currentNumber}</p>
      </div>
    );
  }
}

// Render
ReactDOM.render(<NumberView />, document.getElementById("numberview1"));
odd-number.html
<!DOCTYPE html>
<html lang="en">
   <head>
      <meta charset="UTF-8">
      <title>ReactJS shouldComponentUpdate()</title>
      <script src="https://unpkg.com/react@16.4.2/umd/react.production.min.js"></script>
      <script src="https://unpkg.com/react-dom@16.4.2/umd/react-dom.production.min.js"></script>
      <script src="https://unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>

      <style>
         .number-view  {
         border:1px solid #cbbfab;
         padding: 5px;
         margin: 5px;
         }
      </style>
   </head>
   <body>
      <h1>shouldComponentUpdate():</h1>

      <p>Show only odd numbers</p>
      <div id="numberview1"></div>

      <script src="odd-number.jsx" type="text/babel"></script>
   </body>
</html>

6. UNSAFE_componentWillUpdate (nextProps,nextState)

Phương thức UNSAFE_componentWillUpdate(nextProps,nextState) là nơi cho phép cấu hình hoặc tính toán các giá trị trước khi Component được re-render (vẽ lại). Phương thức này khá giống với phương thức UNSAFE_componentWillMount(), điều khác biệt là trong phương thức này bạn có thể truy cập vào các trạng thái tiếp theo của Component thông qua tham số nextState.
Chú ý: Trong phương thức UNSAFE_componentWillUpdate(nextProps,nextState) bạn không được gọi setState(), bởi nó có thể tạo ra một vòng lặp vô tận.
revenue.jsx
class RevenueView extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      year: 2018,
      revenue: 1000,
      growthRate: "Unknown"
    };
  }

  nextYear() {
    this.setState((prevState, props) => {
      var randomRevenue = prevState.revenue * (1 + Math.random());
      return {
        year: prevState.year + 1,
        revenue: randomRevenue
      };
    });
  }

  UNSAFE_componentWillUpdate(nextProps, nextState) {
    var rate = (nextState.revenue - this.state.revenue) / this.state.revenue;
    nextState.growthRate = 100 * rate + " %";
  }

  render() {
    return (
      <div className="revenue-view">
        <p>Year: {this.state.year}</p>
        <p>Revenue: {this.state.revenue}</p>
        <p>Growth Rate: {this.state.growthRate}</p>
        <button onClick={() => this.nextYear()}>Next Year</button>
      </div>
    );
  }
}

// Render
ReactDOM.render(<RevenueView />, document.getElementById("revenueview1"));
revenue.html
<!DOCTYPE html>
<html lang="en">
   <head>
      <meta charset="UTF-8">
      <title>ReactJS UNSAFE_componentWillUpdate(props,nextState)</title>
      <script src="https://unpkg.com/react@16.4.2/umd/react.production.min.js"></script>
      <script src="https://unpkg.com/react-dom@16.4.2/umd/react-dom.production.min.js"></script>
      <script src="https://unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>

      <style>
         .revenue-view  {
         border:1px solid #cbbfab;
         padding: 5px;
         margin: 5px;
         }
      </style>
   </head>
   <body>
      <h3>UNSAFE_componentWillUpdate(nextProps,nextState):</h3>

      <div id="revenueview1"></div>

      <script src="revenue.jsx" type="text/babel"></script>
   </body>
</html>

7. componentDidUpdate (prevProps,prevState)

  • TODO !!