Когда использовать метод React «componentDidUpdate»?


110

Я написал десятки Reactфайлов, никогда не использую componentDidUpdateметод.

Есть ли типичный пример того, когда нужно использовать этот метод?

Мне нужен реальный пример, а не простая демонстрация.

Спасибо за ответ!



Простой случай, когда вы хотите установить начальное состояние компонента при загрузке.
Раджеш

@Rajesh Можешь объяснить это или привести пример? Спасибо!
slideshowp2

1
Я думаю, что наиболее распространенный вариант использования - это когда у вас есть другие библиотеки (jQuery, D3 ...), которые работают непосредственно с DOM в сочетании с React. В таких сценариях, если другой библиотеке необходимо выполнить преобразования DOM, вы должны использовать componentDidUpdate, чтобы убедиться, что теневой DOM React был сброшен в реальный DOM.
Хорхе

1
Чтобы уточнить комментарий @Jorge: я думаю, что наиболее распространенным случаем было бы ЧТЕНИЕ из реального DOM после обновления React. Например, если вы хотите узнать точные размеры элементов DOM или положение элементов DOM в области просмотра. Например, для анимации или переходов, которыми вы хотите управлять. Я бы определенно посоветовал не использовать jQuery для изменения DOM после того, как реакция была обработана. Реакция + изменение другой библиотеки на тот же фрагмент DOM - плохая идея.
wintvelt

Ответы:


90

Простым примером может служить приложение, которое собирает входные данные от пользователя, а затем использует Ajax для загрузки этих данных в базу данных. Вот упрощенный пример (не запускал - могут быть синтаксические ошибки):

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

Таким образом, всякий раз, когда в компоненте вносятся stateизменения, он автоматически сохраняет данные. Есть и другие способы реализовать это. Это componentDidUpdateособенно полезно, когда необходимо выполнить операцию после обновления DOM и очистки очереди обновления. Это, вероятно , наиболее полезным на сложном rendersи stateили DOM изменение или когда вам нужно что - то , чтобы быть абсолютно последней вещью , которая будет выполнено.

Приведенный выше пример довольно прост, но, вероятно, подтверждает суть дела. Улучшение может заключаться в ограничении количества раз, которое может выполняться автосохранение (например, максимум каждые 10 секунд), потому что прямо сейчас оно будет запускаться при каждом нажатии клавиши.

Я также сделал демонстрацию на этой скрипке, чтобы продемонстрировать.


Для получения дополнительной информации обратитесь к официальной документации :

componentDidUpdate()вызывается сразу после обновления. Этот метод не вызывается для первоначального рендеринга.

Используйте это как возможность работать с DOM после обновления компонента. Это также хорошее место для выполнения сетевых запросов, если вы сравниваете текущие реквизиты с предыдущими реквизитами (например, сетевой запрос может не понадобиться, если реквизиты не изменились).


Я думаю this.setState({...}, callback), callbackравный _commitAutoSave, как вы думаете? Итак, я думаю, что в этом случае можно использовать componentDidUpdateметод, но не обязательно, я прав? fiddle
slideshowp2

1
Да, вы можете использовать обратный вызов, однако проблема становится более сложной, когда / если есть несколько setStates, которые запускаются последовательно.
Крис

Спасибо за Ваш ответ. Итак, один из вариантов componentDidUpdate- решить несколько setStates! Есть другие идеи?
slideshowp2

@novaline Я вижу, что они используют его в компоненте response -sound github.com/leoasis/react-sound/blob/master/src/index.js .. Я не совсем уверен, почему они его используют, но я думал, что поделюсь ссылкой, чтобы вы посмотрели.
Сара

3
Это хороший пример, но в нем отсутствует ключевая рекомендация из документации React. «Это также хорошее место для выполнения сетевых запросов, если вы сравниваете текущие реквизиты с предыдущими (например, сетевой запрос может не понадобиться, если реквизиты не изменились)». reactjs.org/docs/react-component.html#componentdidupdate Точно так же следует заключить вызов в условную логику при каждом вызове setStateв CDU.
theUtherSide

5

Иногда вы можете добавить значение состояния из props в конструктор или componentDidMount, вам может потребоваться вызвать setState, когда props изменились, но компонент уже смонтирован, поэтому componentDidMount не будет выполняться, как и конструктор; в этом конкретном случае вы можете использовать componentDidUpdate, так как реквизиты изменились, вы можете вызвать setState в componentDidUpdate с новыми реквизитами.


2

Я использовал componentDidUpdate()в highchart.

Вот простой пример этого компонента.

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

Этот метод жизненного цикла вызывается, как только происходит обновление. Наиболее распространенный вариант использования метода componentDidUpdate () - это обновление модели DOM в ответ на изменения свойств или состояния.

Вы можете вызвать setState () в этом жизненном цикле, но имейте в виду, что вам нужно будет обернуть его в условие для проверки изменений состояния или поддержки из предыдущего состояния. Неправильное использование setState () может привести к бесконечному циклу. Взгляните на пример ниже, который показывает типичный пример использования этого метода жизненного цикла.

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

Обратите внимание, что в приведенном выше примере мы сравниваем текущие свойства с предыдущими. Это нужно для того, чтобы проверить, изменились ли реквизиты по сравнению с текущими. В этом случае не будет необходимости выполнять вызов API, если свойства не изменились.

Для получения дополнительной информации обратитесь к официальной документации:


Что делать в случае this.fetchData is not a function?
Tomrlh

tomrlh это вызов функции
Кашиф

0

Когда что-то в состоянии изменилось и вам нужно вызвать побочный эффект (например, запрос к api - получить, поставить, опубликовать, удалить). Значит вам нужно позвонить, componentDidUpdate()потому что componentDidMount()это уже называется.

После вызова побочного эффекта в componentDidUpdate () вы можете установить новое значение состояния на основе данных ответа в then((response) => this.setState({newValue: "here"})). Убедитесь, что вам нужно проверить prevPropsили prevStateизбежать бесконечного цикла, потому что при установке нового значения для состояния componentDidUpdate () будет вызывать снова.

Для лучшей практики есть 2 места, где можно вызвать побочный эффект - componentDidMount () и componentDidUpdate ().

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.