Решение проблемы обновления состояния в React: setState
Быстрый ответ
class MyComponent extends React.Component {
_isMounted = false;
componentDidMount() {
this._isMounted = true;
}
componentWillUnmount() {
this._isMounted = false;
}
updateStateIfMounted = (newState) => {
if (this._isMounted) {
this.setState(newState);
}
}
// Замените вызовы this.setState на updateStateIfMounted
}
Чтобы избежать ошибок при попытках обновить состояние размонтированного компонента, предусмотрите переменную _isMounted
. Устанавливайте её в true
в методе componentDidMount
и в false
в componentWillUnmount
. Обновление состояния выполняйте только после проверки этого состояния в специально созданной функции updateStateIfMounted
.
Использование useState и useEffect
Для управления асинхронными операциями в функциональных компонентах следует использовать хук useEffect
, предоставляющий возможность отслеживать побочные эффекты и обеспечить очистку перед удалением компонента.
Мощь очистки в асинхронных операциях
import { useState, useEffect } from 'react';
function MyFunctionComponent() {
const [data, setData] = useState(null);
useEffect(() => {
let didCancel = false;
async function fetchData() {
try {
const response = await fetch('/api/data');
if (!didCancel) {
setData(response.data);
}
} catch (error) {
if (!didCancel) {
console.error(error);
}
}
}
fetchData();
return () => {
didCancel = true;
};
}, []);
return ... // Ваш JSX
}
Учет флага didCancel
помогает обеспечить безопасность операций: его установка в true
в функции очистки исключает безрезультатные попытки обновления состояния.
Мониторинг статуса монтирования компонента через useRef
import { useState, useEffect, useRef } from 'react';
function MyFunctionComponent() {
const [data, setData] = useState(null);
const isMounted = useRef(true);
useEffect(() => {
const fetchData = async () => {
const response = await fetch('/api/data');
if (isMounted.current) {
setData(response.data);
}
};
fetchData();
return () => {
isMounted.current = false;
};
}, []);
return ... // Ваш JSX
}
С помощью useRef
можно отслеживать изменения статуса монтирования, что помогает предотвратить возможные обновления, когда компонент уже отсутствует в DOM.
Эффективность AbortController в асинхронных операциях
import { useState, useEffect } from 'react';
function MyFunctionComponent() {
const [data, setData] = useState(null);
useEffect(() => {
const abortController = new AbortController();
const { signal } = abortController;
async function fetchData() {
try {
const response = await fetch('/api/data', { signal });
setData(response.data);
} catch (error) {
if (error.name !== 'AbortError') {
console.error(error);
}
}
}
fetchData();
return () => abortController.abort();
}, []);
return ... // ваш JSX
}
AbortController
эффективно обрушивает уже не требуемый запрос fetch
, если компонент был размонтирован.
Понимание жизненного цикла и паттернов React
Выяснение жизненного цикла и паттернов React важно для регулирования обновлений и избегания утечек памяти.
Цикл монтирования и демонтирования компонента
Навык подписки и отписки от различных сервисов полезен для уверенной работы компонент и переключения нагрузок и использования памяти.
Реакция на паттерны React
С целью избегания повтора и повышения удобочитаемости кода, используйте кастомные хуки для инкапсуляции логики жизненного цикла и управления асинхронными операциями.
function useFetch(url) {
const [data, setData] = useState(null);
const isMounted = useRef(true);
useEffect(() => {
const fetchData = async () => {
const response = await fetch(url);
if (isMounted.current) {
setData(response.data);
}
};
fetchData();
return () => {
isMounted.current = false;
};
}, [url]);
return data;
}
Применение кастомного хука useFetch
делает код более выразительным и модульным при получении данных.
Визуализация
Представим объявление на пустои клуб:
Клуб 🎒: [Место 1, Место 2, Место 3] (НИКОГО нет)
Объявление 📢: "Завтра состоится викторина!"
Та же история с размонтированным компонентом:
React-компонент (🎒): [Размонтирован]
Обновление состояния (📢): "Доступны новые данные!"
**ПРЕДУПРЕЖДЕНИЕ**: 🚫📢 В компоненте никого нет! Все пользователи (👥) уже покинули его.
Таким образом, обновление состояния для размонтированного компонента можно сравнить с объявлением без слушателей.
Полезные материалы
- Состояние и жизненный цикл – React — ускоренное обучение управлению состоянием и методам жизненного цикла в React.
- isMounted это антипаттерн – Блог React — объяснение, почему применение метода
isMounted()
оценивается как негативная практика. - Использование хука эффекта – React — гайд по использованию
useEffect
для взаимодействия с побочными эффектами в функциональных компонентах. - Нельзя обновить состояние React в размонтированном компоненте – Stack Overflow — водокачку лучших идей можно взять прямо из дискуссий сообщества о данной задаче.
- React как UI-рантайм — overreacted — качественное знакомство с компонентами React в контексте UI-рантайм.
- Полное руководство по useEffect — overreacted — лучшее руководство по
useEffect
от Дэна Абрамова. - Хук setState внутри useEffect может вызвать неизбежное предупреждение Невозможно выполнить обновление состояния React · Issue #14369 · facebook/react · GitHub — глубокий анализ проблемы, представленный на GitHub.