Kiedy używać metody „componentDidUpdate” w React?

110

Napisałem dziesiątki Reactplików, nigdy nie używam componentDidUpdatemetody.

Czy istnieje typowy przykład, kiedy należy skorzystać z tej metody?

Chcę jakiegoś prawdziwego przykładu, a nie prostego demo.

Dziękuję za odpowiedź!

pokaz slajdówp2
źródło
Prosty przypadek, gdy chcesz ustawić początkowy stan elementu podczas ładowania.
Rajesh
@Rajesh Czy możesz to wyjaśnić lub podać przykład? Dzięki!
pokaz
1
Myślę, że najczęstszym przypadkiem użycia jest sytuacja, gdy masz inne biblioteki (jQuery, D3 ...), które działają bezpośrednio na DOM, w połączeniu z React. W takich scenariuszach, jeśli inna biblioteka musi przeprowadzić transformacje DOM, powinieneś użyć componentDidUpdate, aby upewnić się, że cień DOM React został opróżniony do prawdziwego DOM.
Jorge
1
Aby rozwinąć komentarz @ Jorge: Myślę, że najczęstszym przypadkiem byłoby CZYTANIE z prawdziwego DOM po aktualizacji Reacta. Np. Gdy chcesz poznać dokładne wymiary elementów DOM lub położenie elementów DOM w widoku. Np. W przypadku animacji lub przejść, którymi chcesz zarządzać. Zdecydowanie odradzałbym używanie jQuery do zmiany DOM po renderowaniu reakcji. Reakcja + zmiana innej biblioteki tego samego fragmentu DOM jest złym pomysłem.
wintvelt

Odpowiedzi:

90

Prostym przykładem może być aplikacja, która zbiera dane wejściowe od użytkownika, a następnie używa Ajax do przesłania tych danych do bazy danych. Oto uproszczony przykład (nie uruchamiaj go - może zawierać błędy składniowe):

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>
    );
  }
}

Tak więc za każdym razem, gdy składnik ma statezmianę, automatycznie zapisze dane. Istnieją również inne sposoby, aby to wdrożyć. Jest componentDidUpdateto szczególnie przydatne, gdy operacja musi nastąpić po zaktualizowaniu DOM i opróżnieniu kolejki aktualizacji. Jest to prawdopodobnie najbardziej użyteczne na skomplikowane rendersi stateczy DOM zmienia się lub gdy trzeba coś być absolutnie ostatnia rzecz do wykonania.

Powyższy przykład jest dość prosty, ale prawdopodobnie potwierdza to. Poprawa może polegać na ograniczeniu liczby razy, kiedy autozapis może być wykonywany (np. Maksymalnie co 10 sekund), ponieważ teraz będzie on działał przy każdym naciśnięciu klawisza.

Zrobiłem również demo na tych skrzypcach, aby zademonstrować.


Aby uzyskać więcej informacji, zapoznaj się z oficjalną dokumentacją :

componentDidUpdate()jest wywoływana natychmiast po wystąpieniu aktualizacji. Ta metoda nie jest wywoływana przy pierwszym renderowaniu.

Użyj tego jako okazji do operowania na DOM, kiedy komponent został zaktualizowany. Jest to również dobre miejsce do wykonywania żądań sieciowych, o ile porównujesz obecne właściwości z poprzednimi (np. Żądanie sieciowe może nie być konieczne, jeśli właściwości nie uległy zmianie).

Chris
źródło
Myślę this.setState({...}, callback), że callbackrówne _commitAutoSave, co o tym myślisz? Więc myślę, że w tym przypadku można użyć componentDidUpdatemetody, ale nie musi, mam rację? fiddle
slideshowp2
1
Tak, możesz użyć wywołania zwrotnego, jednak problem staje się trudniejszy, gdy / jeśli istnieje wiele setStates, które są uruchamiane kolejno.
Chris
Dziękuję za odpowiedź. Tak więc jednym z przypadków componentDidUpdatejest rozwiązanie wielu setStates! Jakieś inne pomysły?
pokaz
@novaline Widzę, że używają go w komponencie reagowania dźwięku github.com/leoasis/react-sound/blob/master/src/index.js .. Nie jestem do końca pewien, dlaczego go używają, ale pomyślałem, że ja Udostępnij link, abyś mógł rzucić okiem.
Sarah
3
To dobry przykład, ale brakuje w nim kluczowego zalecenia z dokumentacji React. „Jest to również dobre miejsce do wykonywania żądań sieciowych, o ile porównujesz obecne właściwości z poprzednimi (np. Żądanie sieciowe może nie być konieczne, jeśli właściwości nie uległy zmianie)”. actjs.org/docs/react-component.html#componentdidupdate Podobnie, przy każdym wywołaniu setStateCDU należy opakować wywołanie w logikę warunkową .
theUtherSide
5

Czasami możesz dodać wartość stanu z właściwości w konstruktorze lub w module componentDidMount, może być konieczne wywołanie setState, gdy właściwości ulegną zmianie, ale komponent został już zamontowany, więc componentDidMount nie zostanie wykonane, podobnie jak konstruktor; w tym konkretnym przypadku możesz użyć componentDidUpdate, ponieważ właściwości uległy zmianie, możesz wywołać setState w componentDidUpdate z nowymi właściwościami.

Hasan Ahmed
źródło
2

Użyłem componentDidUpdate()w highchart.

Oto prosty przykład tego komponentu.

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' }} />;
  }
}
Asad Link
źródło
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));

    }
}
James Siva
źródło
1

Ta metoda cyklu życia jest wywoływana zaraz po przeprowadzeniu aktualizacji. Najczęstszym przypadkiem użycia metody componentDidUpdate () jest aktualizacja DOM w odpowiedzi na zmiany właściwości lub stanu.

Możesz wywołać metodę setState () w tym cyklu życia, ale pamiętaj, że będziesz musiał opakować ją w warunek, aby sprawdzić zmiany stanu lub właściwości z poprzedniego stanu. Nieprawidłowe użycie setState () może prowadzić do nieskończonej pętli. Spójrz na poniższy przykład, który przedstawia typowy przykład użycia tej metody cyklu życia.

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

Zauważ, że w powyższym przykładzie porównujemy obecne rekwizyty z poprzednimi. Ma to na celu sprawdzenie, czy nastąpiła zmiana w rekwizytach w stosunku do tego, czym jest obecnie. W takim przypadku nie będzie potrzeby wykonywania wywołania API, jeśli właściwości nie ulegną zmianie.

Aby uzyskać więcej informacji, zapoznaj się z oficjalną dokumentacją:

Kashif
źródło
Co robić w przypadku this.fetchData is not a function?
jutro
tomrlh to wywołanie funkcji
Kashif
0

Gdy coś się zmieniło i musisz wywołać efekt uboczny (np. Żądanie api - pobierz, umieść, opublikuj, usuń). Więc musisz zadzwonić, componentDidUpdate()ponieważ componentDidMount()jest już wezwany.

Po wywołaniu efektu ubocznego w componentDidUpdate (), możesz ustawić stan na nową wartość na podstawie danych odpowiedzi w pliku then((response) => this.setState({newValue: "here"})). Upewnij się, że musisz sprawdzić prevPropslub prevStateuniknąć nieskończonej pętli, ponieważ podczas ustawiania stanu na nową wartość, funkcja componentDidUpdate () wywoła ponownie.

Istnieją 2 miejsca, w których można wywołać efekt uboczny dla najlepszych praktyk - componentDidMount () i componentDidUpdate ()

K.tin
źródło