Реагировать крючки. Не удается выполнить обновление состояния React для неустановленного компонента - PullRequest
2 голосов
/ 04 июня 2019

Я получаю эту ошибку:

Невозможно выполнить обновление состояния React на отключенном компоненте.Это не работает, но это указывает на утечку памяти в вашем приложении.Чтобы исправить, отмените все подписки и асинхронные задачи в функции очистки useEffect.

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

Как лучше всего это решить?

Пример CodePen .

default function Test() {
    const [notSeenAmount, setNotSeenAmount] = useState(false)

    useEffect(() => {
        let timer = setInterval(updateNotSeenAmount, 2000) 

        return () => clearInterval(timer)
    }, [])

    async function updateNotSeenAmount() {
        let data // here i fetch data

        setNotSeenAmount(data) // here is problem. If component was unmounted, i get error.
    }

    async function anotherFunction() {
       updateNotSeenAmount() //it can trigger update too
    }

    return <button onClick={updateNotSeenAmount}>Push me</button> //update can be triggered manually
}

1 Ответ

2 голосов
/ 04 июня 2019

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

function Example() {
  const [text, setText] = React.useState("waiting...");

  React.useEffect(() => {
    let isCancelled = false;

    simulateSlowNetworkRequest().then(() => {
      if (!isCancelled) {
        setText("done!");
      }
    });

    return () => {
      isCancelled = true;
    };
  }, []);

  return <h2>{text}</h2>;
}

Вот альтернатива с useRef:

function Example() {
  const isCancelled = React.useRef(false);
  const [text, setText] = React.useState("waiting...");

  React.useEffect(() => {
    fetch();

    return () => {
      isCancelled.current = true;
    };
  }, []);

  function fetch() {
    simulateSlowNetworkRequest().then(() => {
      if (!isCancelled.current) {
        setText("done!");
      }
    });
  }

  return <h2>{text}</h2>;
}

Более подробную информацию об этом шаблоне вы можете найти в этой статье .Вот проблема внутри проекта React на GitHub, которая демонстрирует это решение.

...