#javascript #jquery #reactjs #react-native #use-effect
#javascript #jquery #reactjs #react-native #использование-эффект
Вопрос:
У меня есть следующий код
const Companies = () => {
const [company, setCompany] = useState(plainCompanyObj);
const [companiesData, setCompaniesData] = useState([]);
useEffect(() => {
Call<any, any>({
url:
_baseApiUrl
"-------api goes here --------",
method: "GET",
data: null,
success: (companies) => {
setCompaniesData(companies.companies);
},
authorization: sessionStorage.getItem("accessToken"),
});
}, []);
return (
//return JSX
);
};
Я получаю следующую ошибку: Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
Также просто для уточнения Call
тега — это метод, импортированный axios
тем, который я использую для обработчика ошибок URL и т.д. Проблема, о которой свидетельствует ошибка, находится в useEffect
разделе.
Комментарии:
1. Когда именно вы получаете это сообщение об ошибке?
2. @NemanjaLazarevic У меня есть только один эффект использования в моем проекте, так что это должно быть оно
3. Вы могли бы опубликовать код, в котором вы визуализируете
<Companies />
компонент. Возможно, там у вас есть какая-то логика, которая преждевременно отключает ваш<Companies />
компонент.4. @NemanjaLazarevic Есть еще один компонент под названием LayoutCompanies, который возвращает коробку из MatUI.
<Box> <Companies /> </Box>
5. Очевидно, вы не ожидаете, что этот компонент будет размонтирован (что предполагает ошибка). Чтобы подтвердить, что это так, вы можете добавить a
return () => {console.log("Component Unmounded")}
внизу вашегоuseEffect
. Если после обновления вы видите этот журнал, это означает, что вам нужно искать виновника где-то в дереве компонента.
Ответ №1:
Ваша проблема в том, что вы вызываете setCompaniesData
, когда компонент уже был размонтирован. Итак, вы можете попробовать использовать токен отмены, чтобы отменить запрос axios. https://github.com/axios/axios#cancellation
const Companies = () => {
const [company, setCompany] = useState(plainCompanyObj);
const [companiesData, setCompaniesData] = useState([]);
useEffect(() => {
const cancelTokenSource = axios.CancelToken.source();
Call<any, any>({
url:
_baseApiUrl
"-------api goes here --------",
method: "GET",
data: null,
cancelToken: cancelTokenSource.token
success: (companies) => {
setCompaniesData(companies.companies);
},
authorization: sessionStorage.getItem("accessToken"),
});
}, []);
return () => {
cancelTokenSource.cancel();
}
};
Второй вариант — отслеживать состояние смонтированного компонента и вызывать setState только в том случае, если компонент все еще смонтирован.
Посмотрите это видео здесь: https://www.youtube.com/watch?v=_TleXX0mxaYamp;ab_channel=LeighHalliday
Ответ №2:
Проблема, с которой вы сталкиваетесь, заключается в том, что вы создаете запрос на сервер, в то время как пользователь / вы отключаете (меняете вид / перенаправляете) компонент, который ожидает данных с сервера.
Отмена ajax-запросов — хорошая практика, это не просто реакция.
Axios использует токены отмены для отмены — отмена
По моему опыту, лучше обернуть целые axios в свой собственный код. И обработайте отмену там. (что-то вроде api.get( /route
); api.cancel( /route
))
Надеюсь, это поможет
Ответ №3:
Вот общий пример выборки json axios с отменой асинхронной задачи (живая демонстрация):
import React, { useEffect, useState } from "react";
import { CPromise, CanceledError } from "c-promise2";
import cpAxios from "cp-axios";
function MyComponent(props) {
const [text, setText] = useState("fetching...");
useEffect(() => {
console.log("mount");
const promise = CPromise.from(function* () {
try {
const response = yield cpAxios(props.url);
setText(`Success: ${JSON.stringify(response.data)}`);
} catch (err) {
console.warn(err);
CanceledError.rethrow(err); //passthrough
// handle other errors than CanceledError
setText(`Failed: ${err}`);
}
});
return () => {
console.log("unmount");
promise.cancel(); // cancel async task
};
}, [props.url]);
return <p>{text}</p>;
}