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

Фаза монтирования:этап монтирования происходит, когда экземпляр компонента класса создается и вставляется в DOM. На этом этапе вызываются следующие методы жизненного цикла:

  • конструктор(): метод — это специальный метод в компонентах класса React, который вызывается во время создания экземпляра компонента. Он используется для инициализации состояния компонента и привязки обработчиков событий.
class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
    };
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    this.setState((prevState) => ({
      count: prevState.count + 1,
    }));
  }
  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={this.handleClick}>Increment</button>
      </div>
    );
  }
}

Стоит отметить, что в современном JavaScript и с введением синтаксиса свойств Babel и класса вам не обязательно использовать метод конструктора для настройки состояния и привязки обработчиков событий. Вы можете добиться того же результата, используя инициализаторы свойств класса и стрелочные функции.

class MyComponent extends React.Component {
  state = {
    count: 0,
  };
  handleClick = () => {
      this.setState((prevState) => ({
        count: prevState.count + 1,
      }));
  };
  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={this.handleClick}>Increment</button>
      </div>
    );
  }
}

Важно отметить, что метод конструктора является необязательным в компонентах класса React. Если у компонента нет требований к инициализации состояния или привязке событий, вы можете вообще не использовать конструктор.

  • componentDidMount(): метод жизненного цикла в компонентах класса React вызывается сразу после того, как компонент смонтирован и вставлен в DOM. Он часто используется для инициирования вызовов API, настройки подписок или выполнения любых других задач инициализации, которые должны выполняться после отображения компонента на экране.
class MyComponent extends React.Component {
  componentDidMount() {
    // Perform initialization tasks or side effects
    // Example: Fetch data from an API
    fetch('https://api.example.com/data')
      .then((response) => response.json())
      .then((data) => {
        // Update the component's state with fetched data
        this.setState({ data });
      })
      .catch((error) => {
        // Handle any errors that occurred during the API call
        console.error('Error fetching data:', error);
      });
  }
render() {
    return (
      <div>
        {/* Component rendering and logic */}
      </div>
    );
  }
}

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

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

  • getDerivedStateFromProps(): метод жизненного цикла в компонентах класса React используется для обновления состояния компонента на основе изменений в свойствах. Он вызывается перед рендерингом, как при первоначальном монтировании, так и при последующих обновлениях.
class MyComponent extends React.Component {
  static getDerivedStateFromProps(nextProps, prevState) {
    // Compare current props with next props
    if (nextProps.someProp !== prevState.prevProp) {
      return {
        derivedState: nextProps.someProp,
        prevProp: nextProps.someProp,
      };
    }

    return null; // Return null if no state update is necessary
  }

  state = {
    derivedState: '',
    prevProp: '',
  };

  render() {
    return (
      <div>
        <h1>{this.state.derivedState}</h1>
      </div>
    );
  }
}

В этом примере MyComponent реализует статический метод getDerivedStateFromProps. Он сравнивает текущие свойства (nextProps) с предыдущим значением свойств, хранящимся в состоянии компонента (prevState.prevProp). Если обнаружено изменение, он обновляет состояние компонента, возвращая объект с новыми значениями состояния.

Важно отметить, что getDerivedStateFromProps — это статический метод, то есть он не имеет доступа к экземпляру компонента (this). Он получает следующие реквизиты и предыдущее состояние в качестве аргументов и возвращает объект для обновления состояния или null, если обновление состояния не требуется.

  • shouldComponentUpdate(prevProps, prevState): метод жизненного цикла в компонентах класса React используется для управления тем, должен ли компонент повторно отображаться или нет. Это позволяет оптимизировать производительность, предотвращая ненужные повторные рендеры, когда свойства или состояние компонента не изменились.
class MyComponent extends React.Component {
  state = {
    count: 0,
  };

  shouldComponentUpdate(nextProps, nextState) {
    // Compare current props and state with next props and state
    if (this.props.someProp !== nextProps.someProp) {
      return true; // Re-render if the specific prop has changed
    }

    if (this.state.count !== nextState.count) {
      return true; // Re-render if the state count has changed
    }

    return false; // Skip re-render if no changes
  }

  handleClick = () => {
    this.setState((prevState) => ({
      count: prevState.count + 1,
    }));
  };

  render() {
    return (
      <div>
        <h1>{this.props.someProp}</h1>
        <p>Count: {this.state.count}</p>
        <button onClick={this.handleClick}>Increment</button>
      </div>
    );
  }
}

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

  • getSnapshotBeforeUpdate(prevProps, prevState): Метод жизненного цикла в компонентах класса React используется для сбора информации о модели DOM компонента до того, как она может быть обновлена. Он вызывается непосредственно перед тем, как изменения виртуальной модели DOM отражаются в фактической модели DOM.
class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      messages: [],
    };
    this.containerRef = React.createRef();
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    if (prevProps.messages.length < this.props.messages.length) {
      // Scroll to the bottom of the container before update
      const container = this.containerRef.current;
      return container.scrollHeight - container.scrollTop;
    }
    return null;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    if (snapshot !== null) {
      // Adjust the scroll position after update
      const container = this.containerRef.current;
      container.scrollTop = container.scrollHeight - snapshot;
    }
  }

  render() {
    return (
      <div ref={this.containerRef} style={{ height: '200px', overflow: 'auto' }}>
        {this.props.messages.map((message, index) => (
          <div key={index}>{message}</div>
        ))}
      </div>
    );
  }
}

В этом примере MyComponent реализует метод жизненного цикла getSnapshotBeforeUpdate. Он проверяет, увеличилось ли количество сообщений в props с момента предыдущего обновления. Если это так, он фиксирует положение прокрутки элемента-контейнера перед обновлением.

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

Важно отметить, что getSnapshotBeforeUpdate часто используется в сочетании с componentDidUpdate для обработки сценариев, в которых необходимо сохранить определенную информацию, связанную с DOM.

  • componentDidUpdate(prevProps, prevState): Этот метод вызывается сразу после обновления. Это полезно для выполнения побочных эффектов на основе изменений реквизита или состояния. Обязательно сравните текущие реквизиты и состояние с предыдущими реквизитами и состоянием, чтобы избежать бесконечных циклов обновления. Пример:

Фаза размонтирования. Этап размонтирования происходит, когда компонент удаляется из модели DOM. На этом этапе вызывается следующий метод жизненного цикла:

  • componentWillUnmount(): Этот метод вызывается непосредственно перед размонтированием и уничтожением компонента. Он используется для задач очистки, таких как очистка интервалов или отмена запросов API. Пример:
class MyComponent extends React.Component {
  componentWillUnmount() {
    // Clean up intervals
    // Cancel API requests
  }
  // ...
}

В дополнение к вышеупомянутым методам жизненного цикла существует несколько других менее часто используемых методов, таких как static getDerivedStateFromProps() и shouldComponentUpdate(), которые можно использовать для определенных целей.

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

  1. Фаза монтирования. Фаза монтирования функциональных компонентов относится к инициализации и вставке компонента в DOM. На этом этапе обычно используются следующие крючки:
  • useEffect с пустым массивом зависимостей ([]): этот хук заменяет метод жизненного цикла componentDidMount. Он запускает предоставленную функцию эффекта только один раз, после монтирования компонента. Пример:
import React, { useEffect } from 'react';
function MyComponent() {
  useEffect(() => {
    // Perform initialization tasks
    // Fetch data from an API
    // Set up subscriptions
  }, []);
  // Component rendering and logic...
  return (
    // JSX content
  );
}
  • useEffect без массива зависимостей: этот хук похож на componentDidUpdate и запускает предоставленную функцию эффекта после каждого рендера. Пример:
import React, { useEffect } from 'react';
function MyComponent(props) {
  useEffect(() => {
    // Perform side effects based on prop or state changes
    // Update a global state
    // Make API requests
    // Update a local variable
  });
  // Component rendering and logic...
  return (
    // JSX content
  );
}
  1. Фаза размонтирования. Этап размонтирования происходит, когда функциональный компонент собирается удалить из DOM. Следующий хук обычно используется для очистки ресурсов:
  • useEffect с функцией очистки и пустым массивом зависимостей: этот хук похож на componentWillUnmount и запускает функцию очистки непосредственно перед размонтированием компонента. Пример:
import React, { useEffect } from 'react';
function MyComponent() {
  useEffect(() => {
    // Perform initialization tasks
  return () => {
        // Clean up resources
        // Clear intervals
        // Cancel API requests
      };
    }, []);
    // Component rendering and logic...
    return (
      // JSX content
    );
}

Стоит отметить, что с появлением React Hooks в React 16.8 рекомендуется использовать функциональные компоненты с хуками, а не классовые компоненты. Хуки обеспечивают более краткий и гибкий способ достижения тех же функций, что и методы жизненного цикла компонентов класса.

Не забудьте обратиться к документации React за самой последней информацией о методах жизненного цикла и их использовании в React.