Я прочитал React Docs on Hooks и запутался. Когда вызывается функция очистки useEffect Hook?

Объяснение в ответных документах о том, когда вызывается функция очистки useEffect, сбивает с толку и, если честно, является общим. Они даже больше сбивают вас с толку, сравнивая ментальную модель класса с крючками. Компоненты на основе классов работают иначе, чем компоненты на основе функций с перехватчиками. React запоминает функцию эффекта, которую вы предоставили для useEffect, и запускает ее после сброса изменений в DOM, что понятно. Теперь, как и когда вызывается возвращаемая функция («функция очистки»)?

Пример кода ниже:

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

function FriendStatus(props) {
  const [isOnline, setIsOnline] = useState(null);

  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }

    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    // Specify how to clean up after this effect:
    return function cleanup() {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}

person claOnline    schedule 16.04.2019    source источник


Ответы (2)


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

Пример

const { useEffect, useState } = React;

function MyComponent({ prop }) {
  useEffect(() => {
    console.log('Effect!');
    return () => console.log('Cleanup!')
  }, [prop])

  return (
    <div>{prop}</div>
  );
}

function App() {
  const [value, setValue] = useState(0);

  useEffect(() => {
    setInterval(() => {
      setValue(value => value + 1);
    }, 1000)
  }, [])

  return value < 3 ? <MyComponent prop={value} /> : null;
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>

person Tholle    schedule 16.04.2019
comment
Хорошо, функция очистки запустится после размонтирования, и это нормально, но меня смущает именно размонтирующая часть. Когда это случится? Размонтирование вручную или когда React собирается повторно отобразить компонент, удалив предыдущий из DOM - person claOnline; 16.04.2019
comment
@claOnline Размонтирование происходит, когда компонент больше не отображается, то есть когда value >= 3 в моем примере. Повторный рендеринг компонента из-за изменений свойств, состояния или контекста не отключает компонент. - person Tholle; 16.04.2019
comment
Я запускаю ваш фрагмент кода, но функция очистки по-прежнему работает и выводит сообщение «Очистка!». когда value < 3 - person claOnline; 18.04.2019
comment
@claOnline Да, потому что prop изменяется, что указано в массиве, который является вторым аргументом для useEffect. Функция очистки запускается каждый раз перед повторным запуском эффекта и при размонтировании. - person Tholle; 18.04.2019

Без использования второго параметра он будет вызываться при каждом рендеринге.

Часто это перебор, поэтому часто рекомендуется использовать второй параметр, даже если он пуст [] ..

eg.

useEffect(() => {....}, []);

Выполнение описанного выше вызовет очистку только тогда, когда компонент физически отсоединен от DOM.

Вы также можете передать props вместо [], это удобно, если, скажем, изменение реквизита, например, в какой комнате чата вы были, затем она очистит текущую комнату чата и инициализирует новую комнату чата и т. Д.

Итак, в вашем примере передача [props.friend.id] имеет смысл, потому что, если идентификатор изменится, будет иметь смысл вызвать очистку, а затем снова запустить эффект для нового идентификатора.

person Keith    schedule 16.04.2019