React.js useEffect против (componentDidMount, componentDidUpdate и componentWillUnmount)

В настоящее время существует множество интерфейсных библиотек и фреймворков. Самые популярные из них React.js, Angular.js и Vue.js. У каждого из них есть свое место в отрасли. И людям они очень нравятся из-за их способности рендерить и манипулировать DOM во время выполнения. Они могут сделать это, сохраняя состояние компонентов приложения. Сегодня мы поговорим о React и методах его жизненного цикла.

React — это популярная внешняя библиотека JavaScript для создания пользовательских интерфейсов, которая предоставляет ряд функций и инструментов, упрощающих и повышающих эффективность разработки. Одним из наиболее важных аспектов React является управление жизненным циклом компонентов, что может существенно повлиять на производительность, стабильность и удобство работы пользователей.

В этом сообщении блога мы рассмотрим различия между useEffect и методами жизненного цикла компонентов класса (componentDidMount, componentDidUpdate и componentWillUnmount) и объясним, когда и почему вы можете предпочесть один из них другому. Поняв эти различия, вы сможете писать более эффективный и действенный код React, обеспечивающий лучшие результаты для ваших пользователей.

компонентDidMount:

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

Когда вызывается componentDidMount, реквизиты и состояние компонента уже были установлены, а метод рендеринга компонента был вызван, что означает, что все дочерние компоненты также были смонтированы. Это делает безопасным место для выполнения любых необходимых операций, которые зависят от дочерних или родительских компонентов компонента.

Важно отметить, что componentDidMount вызывается только один раз за время жизни компонента. После первоначального монтирования последующие обновления компонента не вызовут componentDidMount. Если вам нужно выполнить обновления или очистку после первоначального монтирования, вместо этого следует использовать метод жизненного цикла componentDidUpdate.

Пример:

import React, { Component } from 'react';

class MyComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      data: null,
    };
  }

  componentDidMount() {
    // Fetch data from a server after the component has mounted
    fetch('https://example.com/data')
      .then(response => response.json())
      .then(data => this.setState({ data }));
  }

  render() {
    return (
      <div>
        {/* Render the data once it has been fetched */}
        {this.state.data && <p>{this.state.data}</p>}
      </div>
    );
  }
}

В этом примере класс MyComponent расширяет класс Component и определяет объект состояния со свойством data, инициализированным значением null. В методе componentDidMount компонент использует API fetch для асинхронной выборки данных с сервера, а затем устанавливает свойство data в состояние с помощью this.setState. Как только данные будут получены и установлены в состояние, метод компонента render будет вызываться снова, на этот раз отображая полученные данные.

componentDidMount и useEffect:

import React, { useState, useEffect } from 'react';

function MyComponent() {
  const [data, setData] = useState(null);

  useEffect(() => {
    // Fetch data from a server after the component has mounted
    fetch('https://example.com/data')
      .then(response => response.json())
      .then(data => setData(data));
  }, []); // Empty dependency array ensures the effect runs only once, like componentDidMount

  return (
    <div>
      {/* Render the data once it has been fetched */}
      {data && <p>{data}</p>}
    </div>
  );
}

В этом примере функция MyComponent определяет переменную состояния data, инициализированную значением null, и использует хук useEffect для получения данных с сервера после монтирования компонента. Второй аргумент useEffect — это пустой массив, который гарантирует, что эффект запускается только один раз, имитируя поведение componentDidMount. Как только данные будут извлечены и установлены с помощью функции setData, компонент будет повторно визуализировать, на этот раз отображая извлеченные данные.

компонентDidUpdate:

componentDidUpdate — это метод жизненного цикла в компонентах класса React, который вызывается после обновления компонента и повторно отображается в DOM. Этот метод полезен для выполнения любых побочных эффектов, которые зависят от изменений свойств или состояния компонента.

Когда вызывается componentDidUpdate, к предыдущим реквизитам и состоянию компонента можно получить доступ с помощью объектов this.props и this.state, а к текущим реквизитам и состоянию можно получить доступ с помощью аргументов nextProps и nextState, переданных методу.

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

Если вам нужно обновить состояние в ответ на изменения в свойствах, вы должны вместо этого использовать метод static getDerivedStateFromProps, так как он вызывается перед render и не вызывает лишнего повторного рендеринга.

Пример:

import React, { Component } from 'react';

class MyComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
    };
  }

  componentDidUpdate(prevProps, prevState) {
    // Log the previous and current count values when the count changes
    if (this.state.count !== prevState.count) {
      console.log(`Count changed from ${prevState.count} to ${this.state.count}`);
    }
  }

  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Increment Count
        </button>
      </div>
    );
  }
}

В этом примере класс MyComponent расширяет класс Component и определяет объект состояния со свойством count, инициализированным значением 0. В методе componentDidUpdate компонент проверяет, отличается ли текущее значение count от предыдущего значения count, хранящегося в prevState, и записывает сообщение в консоль, если оно изменилось.

Метод render компонента отображает текущее значение count и кнопку, которая обновляет счетчик при нажатии. Всякий раз, когда значение count обновляется, компонент будет повторно отображаться, и будет вызываться componentDidUpdate, регистрируя сообщение на консоли, если значение count изменилось.

componentDidUpdate и useEffect:

import React, { useState, useEffect } from 'react';

function MyComponent(props) {
  const [count, setCount] = useState(0);

  useEffect(() => {
    // Log the previous and current count values when the count changes
    console.log(`Count changed from ${prevCount} to ${count}`);
  }, [count]); // Run the effect whenever the count changes

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={handleClick}>Increment Count</button>
    </div>
  );
}

В этом примере функция MyComponent определяет переменную состояния count, инициализированную значением 0, и использует хук useEffect для регистрации сообщения на консоли при каждом изменении счетчика. Второй аргумент useEffect — это массив, содержащий переменную count, которая гарантирует, что эффект запускается только при изменении счетчика, имитируя поведение componentDidUpdate.

Функция handleClick обновляет счетчик, вызывая функцию setCount с текущим счетчиком плюс 1. Когда счетчик обновляется, компонент повторно визуализируется, запуская хук useEffect и записывая сообщение на консоль, если счетчик изменился.

componentWillUnmount:

componentWillUnmount — это метод жизненного цикла в компонентах класса React, который вызывается непосредственно перед размонтированием компонента и его удалением из DOM. Этот метод полезен для выполнения любых необходимых операций очистки или удаления, таких как отмена таймеров, удаление прослушивателей событий или очистка данных из кэша.

При вызове componentWillUnmount компонент должен очистить все ресурсы, которые были созданы или использованы в течение его жизненного цикла. Если компонент установил какие-либо подписки или прослушиватели, например, в методе componentDidMount, он должен удалить их в componentWillUnmount, чтобы избежать утечек памяти или нежелательных побочных эффектов.

Важно отметить, что componentWillUnmount вызывается только один раз, когда компонент размонтируется. Следовательно, это хорошее место для выполнения любых операций очистки, которые должны выполняться только один раз, а не в componentDidUpdate, который вызывается после каждого обновления.

Пример:

import React, { Component } from 'react';

class MyComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
    };
    this.timerId = null;
  }

  componentDidMount() {
    // Start a timer that updates the count every second
    this.timerId = setInterval(() => {
      this.setState({ count: this.state.count + 1 });
    }, 1000);
  }

  componentWillUnmount() {
    // Clean up the timer before the component is unmounted
    clearInterval(this.timerId);
  }

  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
      </div>
    );
  }
}

В этом примере класс MyComponent расширяет класс Component и определяет объект состояния со свойством count, инициализированным значением 0. В методе componentDidMount компонент запускает таймер, который обновляет счетчик каждую секунду, и сохраняет идентификатор таймера в this.timerId.

В методе componentWillUnmount компонент сбрасывает таймер с помощью clearInterval, чтобы предотвратить его дальнейшее выполнение после размонтирования компонента.

Метод render компонента отображает текущее значение count. Когда компонент размонтирован, вызывается componentWillUnmount для очистки таймера и предотвращения дальнейших обновлений состояния.

componentWillUnmount и useEffect:

import React, { useState, useEffect } from 'react';

function MyComponent() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const timerId = setInterval(() => {
      setCount(count => count + 1);
    }, 1000);

    return () => {
      clearInterval(timerId);
    };
  }, []); // Run the effect only once on mount

  return (
    <div>
      <p>Count: {count}</p>
    </div>
  );
}

В этом примере функция MyComponent использует useEffect для запуска таймера, который каждую секунду обновляет переменную состояния count. Хук useEffect возвращает функцию очистки, которая очищает таймер с помощью clearInterval.

Пустой массив зависимостей ([]), переданный в качестве второго аргумента useEffect, гарантирует, что эффект запускается только один раз при монтировании компонента, а не при каждом обновлении.

Когда компонент размонтирован, вызывается функция очистки, возвращаемая useEffect, которая очищает таймер, чтобы предотвратить дальнейшие обновления состояния.

Используя useEffect для обработки операций очистки, мы можем избежать необходимости определять отдельный метод componentWillUnmount в компонентах класса и сделать наш код более кратким и читабельным.

useEffect:

В функциональных компонентах хук useEffect можно использовать для достижения той же функциональности, что и методы жизненного цикла компонентов класса. Хук useEffect принимает функцию в качестве первого аргумента и запускает эту функцию после рендеринга компонента. Функция может возвращать функцию очистки, которая будет вызываться при размонтировании компонента.

Ключевые отличия:

Вот некоторые ключевые различия между хуком useEffect и методами жизненного цикла компонента класса:

  • useEffect заменяет все три метода жизненного цикла компонентов класса одним хуком.
  • В отличие от componentDidMount, хук useEffect запускается после каждого рендеринга компонента (если только хуку не передается второй аргумент, чтобы указать, когда его перезапускать).
  • useEffect не имеет прямого эквивалента componentDidUpdate, но его можно использовать для достижения той же функциональности, включив соответствующее состояние или реквизиты в массив зависимостей, переданный в качестве второго аргумента для useEffect.
  • Функция очистки, возвращаемая useEffect, по функциональности похожа на componentWillUnmount, но она запускается после каждого рендеринга, а не только при размонтировании компонента.

"Спасибо за чтение! Если вам понравился этот пост, обязательно ознакомьтесь с некоторыми из моих других статей. Вы также можете найти меня в LinkedIn, где мы можем более подробно поговорить, и вы можете порекомендовать мне изменения или новые темы, которые вам нужно добавить. Давайте подключимся и продолжим общение!»