Khi nào sử dụng phương thức React “componentDidUpdate”?


109

Tôi đã viết hàng chục Reacttệp, không bao giờ sử dụng componentDidUpdatephương pháp.

Có ví dụ điển hình nào về thời điểm cần sử dụng phương pháp này không?

Tôi muốn một số ví dụ trong thế giới thực, không phải một bản demo đơn giản.

Cảm ơn vì câu trả lời!



Một trường hợp đơn giản khi bạn muốn thiết lập trạng thái ban đầu của thành phần khi tải.
Rajesh

@Rajesh Bạn có thể giải thích hoặc cho tôi một ví dụ được không? Cảm ơn!
slideshowp 2

1
Tôi nghĩ rằng trường hợp sử dụng phổ biến nhất là khi bạn có các thư viện khác (jQuery, D3 ...) hoạt động trực tiếp trên DOM, cùng với React. Trong các tình huống như vậy, nếu thư viện khác cần thực hiện các phép biến đổi DOM, bạn nên sử dụng componentDidUpdate để đảm bảo DOM bóng của React đã được chuyển sang DOM thực.
Jorge

1
Để giải thích rõ hơn về nhận xét của @ Jorge: Tôi nghĩ trường hợp phổ biến nhất sẽ là ĐỌC từ DOM thực sau khi React đã cập nhật. Ví dụ: khi bạn muốn biết kích thước chính xác của các phần tử DOM hoặc vị trí của các phần tử DOM trong chế độ xem. Ví dụ: đối với hoạt ảnh hoặc chuyển đổi mà bạn muốn phản ứng để quản lý. Tôi chắc chắn sẽ khuyên bạn không nên sử dụng jQuery để thay đổi DOM sau khi phản ứng được hiển thị. Có phản ứng + thư viện khác thay đổi cùng một phần DOM là một ý tưởng tồi.
wintvelt

Câu trả lời:


89

Một ví dụ đơn giản sẽ là một ứng dụng thu thập dữ liệu đầu vào từ người dùng và sau đó sử dụng Ajax để tải dữ liệu đó lên cơ sở dữ liệu. Đây là một ví dụ đơn giản (chưa chạy - có thể có lỗi cú pháp):

export default class Task extends React.Component {
  
  constructor(props, context) {
    super(props, context);
    this.state = {
      name: "",
      age: "",
      country: ""
    };
  }

  componentDidUpdate() {
    this._commitAutoSave();
  }

  _changeName = (e) => {
    this.setState({name: e.target.value});
  }

  _changeAge = (e) => {
    this.setState({age: e.target.value});
  }

  _changeCountry = (e) => {
    this.setState({country: e.target.value});
  }

  _commitAutoSave = () => {
    Ajax.postJSON('/someAPI/json/autosave', {
      name: this.state.name,
      age: this.state.age,
      country: this.state.country
    });
  }

  render() {
    let {name, age, country} = this.state;
    return (
      <form>
        <input type="text" value={name} onChange={this._changeName} />
        <input type="text" value={age} onChange={this._changeAge} />
        <input type="text" value={country} onChange={this._changeCountry} />
      </form>
    );
  }
}

Vì vậy, bất cứ khi nào thành phần có statethay đổi nó sẽ tự động lưu dữ liệu. Có nhiều cách khác để thực hiện nó quá. Điều componentDidUpdatenày đặc biệt hữu ích khi một hoạt động cần phải xảy ra sau khi DOM được cập nhật và hàng đợi cập nhật được làm trống. Nó có lẽ hữu ích nhất đối với các thay đổi phức tạp rendersstateDOM hoặc khi bạn cần một thứ gì đó là thứ hoàn toàn cuối cùng được thực thi.

Ví dụ trên khá đơn giản, nhưng có lẽ chứng minh được điểm này. Một cải tiến có thể là giới hạn số lần lưu tự động có thể thực thi (ví dụ: tối đa 10 giây một lần) vì ngay bây giờ nó sẽ chạy trên mọi hành trình phím.

Tôi cũng đã thực hiện một bản demo về trò chơi này để chứng minh.


Để biết thêm thông tin, hãy tham khảo tài liệu chính thức :

componentDidUpdate()được gọi ngay sau khi cập nhật xảy ra. Phương thức này không được gọi cho kết xuất ban đầu.

Sử dụng điều này như một cơ hội để hoạt động trên DOM khi thành phần đã được cập nhật. Đây cũng là một nơi tốt để thực hiện các yêu cầu mạng miễn là bạn so sánh các đạo cụ hiện tại với các đạo cụ trước đó (ví dụ: yêu cầu mạng có thể không cần thiết nếu đạo cụ không thay đổi).


Tôi nghĩ this.setState({...}, callback), callbackbằng nhau _commitAutoSave, bạn nghĩ sao? Vì vậy, tôi nghĩ trường hợp này có thể sử dụng componentDidUpdatephương pháp, nhưng không phải, đúng không? fiddle
slideshowp 2

1
Có, bạn có thể sử dụng callback, tuy nhiên vấn đề trở nên phức tạp hơn khi / nếu có nhiều setState được chạy liên tiếp.
Chris

Cảm ơn câu trả lời của bạn. Vì vậy, một trường hợp cần sử dụng componentDidUpdatelà giải quyết nhiều setStates! Bất kỳ ý tưởng khác?
slideshowp2

@novaline Tôi thấy họ sử dụng nó trong thành phần âm thanh phản ứng github.com/leoasis/react-sound/blob/master/src/index.js .. Tôi không chắc tại sao họ lại sử dụng nó nhưng tôi nghĩ mình sẽ chia sẻ liên kết cho bạn để xem.
Sarah

3
Đây là một ví dụ điển hình, nhưng nó thiếu một đề xuất chính từ tài liệu React. "Đây cũng là một nơi tốt để thực hiện yêu cầu mạng miễn là bạn so sánh đạo cụ hiện tại với đạo cụ trước đó (ví dụ: yêu cầu mạng có thể không cần thiết nếu đạo cụ không thay đổi)." reactjs.org/docs/react-component.html#componentdidupdate Tương tự, người ta nên gói lệnh gọi trong logic có điều kiện bất cứ khi nào gọi setStatetrong CDU.
theUtherSide

5

Đôi khi bạn có thể thêm giá trị trạng thái từ props trong constructor hoặc componentDidMount, bạn có thể cần gọi setState khi props thay đổi nhưng thành phần đã được gắn kết nên componentDidMount sẽ không thực thi và constructor cũng vậy; trong trường hợp cụ thể này, bạn có thể sử dụng componentDidUpdate vì các đạo cụ đã thay đổi, bạn có thể gọi setState trong componentDidUpdate với các đạo cụ mới.


2

Tôi đã sử dụng componentDidUpdate()trong highchart.

Đây là một ví dụ đơn giản về thành phần này.

import React, { PropTypes, Component } from 'react';
window.Highcharts = require('highcharts');

export default class Chartline extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      chart: ''
    };
  }

  public componentDidUpdate() {
    // console.log(this.props.candidate, 'this.props.candidate')
    if (this.props.category) {
      const category = this.props.category ? this.props.category : {};
      console.log('category', category);
      window.Highcharts.chart('jobcontainer_' + category._id, {
        title: {
          text: ''
        },
        plotOptions: {
          series: {
            cursor: 'pointer'
          }
        },
        chart: {
          defaultSeriesType: 'spline'
        },
        xAxis: {
          // categories: candidate.dateArr,
          categories: ['Day1', 'Day2', 'Day3', 'Day4', 'Day5', 'Day6', 'Day7'],
          showEmpty: true
        },
        labels: {
          style: {
            color: 'white',
            fontSize: '25px',
            fontFamily: 'SF UI Text'
          }
        },
        series: [
          {
            name: 'Low',
            color: '#9B260A',
            data: category.lowcount
          },
          {
            name: 'High',
            color: '#0E5AAB',
            data: category.highcount
          },
          {
            name: 'Average',
            color: '#12B499',
            data: category.averagecount
          }
        ]
      });
    }
  }
  public render() {
    const category = this.props.category ? this.props.category : {};
    console.log('render category', category);
    return <div id={'jobcontainer_' + category._id} style={{ maxWidth: '400px', height: '180px' }} />;
  }
}

2
componentDidUpdate(prevProps){ 

    if (this.state.authToken==null&&prevProps.authToken==null) {
      AccountKit.getCurrentAccessToken()
      .then(token => {
        if (token) {
          AccountKit.getCurrentAccount().then(account => {
            this.setState({
              authToken: token,
              loggedAccount: account
            });
          });
        } else {
          console.log("No user account logged");
        }
      })
      .catch(e => console.log("Failed to get current access token", e));

    }
}

1

Phương thức vòng đời này được gọi ngay sau khi cập nhật xảy ra. Trường hợp sử dụng phổ biến nhất cho phương thức componentDidUpdate () là cập nhật DOM để đáp ứng với các thay đổi về trạng thái hoặc chống đỡ.

Bạn có thể gọi setState () trong vòng đời này, nhưng hãy nhớ rằng bạn sẽ cần bao bọc nó trong một điều kiện để kiểm tra các thay đổi trạng thái hoặc prop so với trạng thái trước đó. Việc sử dụng setState () không chính xác có thể dẫn đến một vòng lặp vô hạn. Hãy xem ví dụ dưới đây cho thấy một ví dụ sử dụng điển hình của phương pháp vòng đời này.

componentDidUpdate(prevProps) {
 //Typical usage, don't forget to compare the props
 if (this.props.userName !== prevProps.userName) {
   this.fetchData(this.props.userName);
 }
}

Lưu ý trong ví dụ trên rằng chúng ta đang so sánh các đạo cụ hiện tại với các đạo cụ trước đó. Điều này là để kiểm tra xem có sự thay đổi trong đạo cụ so với hiện tại hay không. Trong trường hợp này, sẽ không cần thực hiện lệnh gọi API nếu các đạo cụ không thay đổi.

Để biết thêm thông tin, hãy tham khảo tài liệu chính thức:


Làm gì trong trường hợp this.fetchData is not a function?
tomrlh

tomrlh đó là một cuộc gọi hàm
Kashif

0

Khi một thứ gì đó ở trạng thái đã thay đổi và bạn cần gọi một hiệu ứng phụ (như yêu cầu api - lấy, đặt, đăng, xóa). Vì vậy, bạn cần phải gọi componentDidUpdate()componentDidMount()đã được gọi.

Sau khi gọi hiệu ứng phụ trong componentDidUpdate (), bạn có thể đặt trạng thái thành giá trị mới dựa trên dữ liệu phản hồi trong then((response) => this.setState({newValue: "here"})). Hãy đảm bảo rằng bạn cần kiểm tra prevPropshoặc prevStateđể tránh vòng lặp vô hạn vì khi đặt trạng thái thành giá trị mới, componentDidUpdate () sẽ gọi lại.

Có 2 nơi để gọi một tác dụng phụ cho phương pháp hay nhất - componentDidMount () và componentDidUpdate ()

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.