- PVSM.RU - https://www.pvsm.ru -
Доброго времени суток!
Все reactjs [1] разработчики, кто имеет дело с интерактивностью между бэком и фронтом рано или поздно встречаются, или встречались, или встретятся со следующей ошибкой:
Если дословно, то получится так:
Предупреждение. Невозможно выполнить обновление состояния React для неустановленного компонента. Это не операция, но она указывает на утечку памяти в вашем приложении. Чтобы исправить, отмените все подписки и асинхронные задачи в функции очистки useEffect.
На самом деле все достаточно просто, нужно всего лишь обратить внимание на следующие словосочетания:
В основе хуки. GO в под кат!
Итак:
Воспроизведем ошибку:
Допустим, мы разрабатываем сайт с подгрузкой описания фильмов (не будем углубляться в API moviedb [5], а возьмем за основу конкретный фильм). У нас есть две странички:
Ссылки на обе странички доступны в навигационной панели, например в header. На главной страничке («Домой») происходит общение с бэком для подгрузки информации о фильме.
/src/Pages/HomePage.js
import React, { useState, useEffect } from 'react';
import { MOVIE_DB_GET } from '../config';
const HomePage = () => {
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(MOVIE_DB_GET);
const result = await response.json();
console.log(result, 'result')
} catch (e) {
console.error(e.message)
}
};
// Произведем get-запрос на информацию о конкретном фильме
fetchData();
}, []);
return (
<main>
<h2>Главная страница</h2>
</main>
)
};
export default HomePage;
/src/Pages/AboutPage.js
import React from 'react';
const AboutPage = () => {
return (
<main>
<h2>О нас</h2>
<p>
Некий контент
</p>
</main>
)
};
export default AboutPage;
Для отображения информации посредством запроса необходимо записать информацию в состояние для последующего рендера:
/src/Pages/HomePage.js
import React, { useState, useEffect } from 'react';
import { MOVIE_DB_GET } from '../config';
const HomePage = () => {
// movie - react-состояние;
// setMovie - функция обновления react-состояния
const [ movie, setMovie ] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(MOVIE_DB_GET);
const result = await response.json();
console.log(result, 'result');
setMovie(result);
} catch (e) {
console.error(e.message)
}
};
// Произведем запрос на информацию о конкретном фильме
fetchData();
}, []);
// descriptionMovie - некая функция, возвращающая view, то есть рендерит информацию о фильме посредством состояния movie
return (
<main>
<h2>Главная страница</h2>
<p>Описание фильма</p>
{
movie ? descriptionMovie() : false
}
</main>
)
};
export default HomePage;
Воспроизведем ошибку следующим путем — переключимся с одного маршрута на другой, то есть находясь на страничке “О нас”, мы перейдем на страничку “Домой” и незамедлительно вернемся снова на страничку “О нас” и вуаля “Can’t perform …..”.
Дело в том, что на запросы сервер не отвечает мгновенно, используется асинхронность, чтобы все таки воспроизвести запрос параллельно необходимым задачам. Но в случае быстрого возврата на страничку “О нас”, компонент “Домой” размонтируется, а значит состояние для данного компонента сброситься, но асинхронность запроса все же запустит setMovie, которого больше нет и выкинет ошибку. Оптимальным решением является запретить использовать обновление состояния при размонтировании компонента:
/src/Pages/HomePage.js
import React, { useState, useEffect } from 'react';
import { MOVIE_DB_GET } from '../config';
const HomePage = () => {
// movie - react-состояние;
// setMovie - функция обновления react-состояния
const [ movie, setMovie ] = useState(null);
useEffect(() => {
let cleanupFunction = false;
const fetchData = async () => {
try {
const response = await fetch(MOVIE_DB_GET);
const result = await response.json();
console.log(result, 'result')
// непосредственное обновление состояния при условии, что компонент не размонтирован
if(!cleanupFunction) setMovie(result);
} catch (e) {
console.error(e.message)
}
};
fetchData();
// функция очистки useEffect
return () => cleanupFunction = true;
}, []);
// descriptionMovie - некая функция, возвращающая view, то есть рендерит информацию о фильме посредством состояния movie
return (
<main>
<h2>Главная страница</h2>
<p>Описание фильма</p>
{
movie ? descriptionMovie() : false
}
</main>
)
};
export default HomePage;
Итого:
Весь исходный код можно посмотреть здесь: https://gitlab.com/ImaGadzhiev/react-cant-perform [8]
Автор: Имран Гаджиев
Источник [9]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/350452
Ссылки в тексте:
[1] reactjs: https://ru.reactjs.org/
[2] состояние: https://ru.reactjs.org/docs/hooks-state.html
[3] useEffect: https://ru.reactjs.org/docs/hooks-effect.html
[4] return () => {} в useEffect: https://ru.reactjs.org/docs/hooks-effect.html#effects-with-cleanup
[5] API moviedb: https://developers.themoviedb.org/3/getting-started/introduction
[6] try/catch: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch
[7] async/await: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
[8] https://gitlab.com/ImaGadzhiev/react-cant-perform: https://gitlab.com/ImaGadzhiev/react-cant-perform
[9] Источник: https://habr.com/ru/post/493496/?utm_source=habrahabr&utm_medium=rss&utm_campaign=493496
Нажмите здесь для печати.