我在Redux中使用React。我编写了一个名为产品的操作,以使用Axios从后端获取产品详细信息。这样,如果用户在此过程中导航到另一个页面,我就使用了取消令牌来取消HTTP请求。
但是,当我导航到另一个页面时,仍然出现如下所示的控制台错误。
index.js:1 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.
当我导航到同一产品页面以获取数据时,请求将转到catch块以引发错误。我使用下面的代码调度操作。
product.js作为操作
const source = Axios.CancelToken.source();
const fetchProducts = () => {
return async (dispatch) => {
try {
const response = await Axios.get("myurl", {
cancelToken: source.token,
});
if (response.status !== 200) {
throw new Error("Something went wrong, while fetching the products!");
}
dispatch({ type: GET_PRODUCTS, products: response.data });
} catch (err) {
if (Axios.isCancel(err)) {
console.log(err.message);
} else {
throw err;
}
}
};
};
const cancelRequest = () => {
return (dispatch) => {
if (source !== typeof undefined) {
source.cancel("Operation canceled by the user.");
dispatch({ type: CANCEL_REQUEST, message: "Request canceled by user!" });
}
};
};
组件文件:
const loadProducts = useCallback(async () => {
setError(null);
try {
await dispatch(productActions.fetchProducts());
} catch (err) {
setError(err.message);
}
}, [dispatch, setError]);
useEffect(() => {
setIsLoading(true);
loadProducts().then(() => {
setIsLoading(false);
});
return () => {
dispatch(productActions.cancelRequest());
};
}, [dispatch, loadProducts, setIsLoading]);
如何解决此问题?
答案 0 :(得分:1)
您正在unmount
上取消请求。取消后,您将进入loadProducts
的catch块。在那儿,您正在设置状态setError(...)
。因此,当您尝试在未安装的组件上设置状态时,会收到错误消息。
要解决此问题,只需不要在catch块中设置状态。根据您的代码,似乎不需要设置错误状态。如果需要,可以从商店购买(因为减速机CANCEL_REQUEST
会显示此消息)
const loadProducts = useCallback(async () => {
setError(null);
try {
await dispatch(productActions.fetchProducts());
} catch (err) {
//setError(err.message); //<----- this is the issue, remove this line
}
}, [dispatch, setError]);
useEffect(() => {
setIsLoading(true);
loadProducts().then(() => {
setIsLoading(false);
});
return () => {
dispatch(productActions.cancelRequest());
};
}, [dispatch, loadProducts, setIsLoading]);
编辑基于评论:
进行以下更改,即可正常运行。
then
块,然后再放置catch
块setError
,因此不需要try / catch块代码段
const useAxiosFetch = url => {
const [data, setData] = useState(null)
const [error, setError] = useState(null)
const [loading, setLoading] = useState(false)
useEffect(() => {
let source = axios.CancelToken.source()
setLoading(true)
axios
.get(url, {
cancelToken: source.token,
})
.then(a => {
console.log('here')
setData(a)
setLoading(false)
})
.catch(function(thrown) {
//put catch after then
if (axios.isCancel(thrown)) {
console.log(`request cancelled:${thrown.message}`)
} else {
console.log('another error happened')
setData(null)
setError(thrown)
}
// throw (thrown)
})
if (source) {
console.log('source defined')
} else {
console.log('source NOT defined')
}
return function() {
console.log('cleanup of useAxiosFetch called')
if (source) {
console.log('source in cleanup exists')
} else {
source.log('source in cleanup DOES NOT exist')
}
source.cancel('Cancelling in cleanup')
}
}, [])
return {data, loading, error}
}