Это общий вариант использования для извлечения и отображения данных из внешнего API (с помощью запросов XHR) при нажатии определенного компонента пользовательского интерфейса (например, <button />
). Однако, если компонент тем временем был размонтирован, в консоли появляется следующее предупреждение:
Предупреждение. Невозможно выполнить обновление состояния React для отключенного компонента. Это не работает, но это указывает на утечку памяти в вашем приложении. Чтобы исправить, отмените все подписки и асинхронные задачи в функции очистки useEffect.
На самом деле, наиболее распространенное решение ( одобренное @ dan-abramov ), позволяющее избежать предупреждения, похоже, отслеживает состояние монтирования компонента с помощью функции возврата useEffect
для очистки .
import React, { useState, useRef, useEffect } from "react";
import axios from "axios";
export default function PhotoList() {
const mounted = useRef(true);
const [photos, setPhotos] = useState(null);
useEffect(() => {
return () => {
mounted.current = false;
};
}, []);
function handleLoadPhotos() {
axios("https://jsonplaceholder.typicode.com/photos").then(res => {
if (mounted.current) {
setPhotos(res.data);
}
});
}
return (
<div>
<button onClick={handleLoadPhotos}>Load photos</button>
{photos && <p>Loaded {photos.length} photos</p>}
</div>
);
}
Однако, похоже, это приводит к ненужным накладным расходам, чтобы отслеживать состояние подключения и проверять его перед каждым обновлением состояния. Это становится особенно очевидным, когда вместо Обещаний используются Observables (где вы можете отписаться ).
Хотя вы действительно можете отписаться внутри useEffect
, используя функцию очистки очень аккуратно:
useEffect(() => {
// getPhotos() returns an observable of the photo list
const photos$ = getPhotos().subscribe(setPhotos);
return () => photos$.unsubscribe();
}, []);
Такая же интеллектуальная очистка невозможна в обработчике:
function handleLoadPhotos() {
const photos$ = getPhotos().subscribe(setPhotos);
// how to unsubscribe on unmounting?
}
Есть ли лучший способ избежать предупреждения без уродливого ручного отслеживания состояния монтажа с помощью useRef()
? Есть ли хорошие подходы для этого при использовании Observables?