我不断收到这些警告:
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
对于我在 useReducer 的帮助下从 API 中提取数据的一些 useEffects:
export default function HomeBucketsExample(props) {
const {mobileView} = props
const [allDemoBuckets, dispatchAllBuckets] = useReducer(reducer, initialStateAllBuckets)
const ListLoading = LoadingComponent(HomeBucketLists);
useEffect(() =>
{
getAllDemoBuckets(dispatchAllBuckets);
}, [])
return (
<ListLoading mobileView={ mobileView} isLoading={allDemoBuckets.loading} buckets={allDemoBuckets.data} />
);
}
但是,我不确定如何清除上面的这种效果,我尝试使用 True
和 False
安装它,但是错误仍然出现。如何修复上面的函数,以便 useEffect 不会抛出任何警告
编辑: 我的 reduer 代码:
export const getAllDemoBuckets = (dispatch) => axiosInstance
.get('demo/all/')
.then(response => {
dispatch({ type: 'FETCH_SUCCESS', payload: response.data })
console.log('fired bucket-data')
})
.catch(error => {
dispatch({ type: 'FETCH_ERROR' })
})
const initialStateAllBuckets = {
loading: true,
error: '',
data: []
}
const reducer = (state, action) =>
{
switch (action.type)
{
case 'FETCH_SUCCESS':
return {
loading: false,
data: action.payload,
error: ''
}
case 'FETCH_ERROR':
return {
loading: false,
data: {},
error: "Something went wrong!"
}
default:
return state
}
}
const [allDemoBuckets, dispatchAllBuckets] = useReducer(reducer, initialStateAllBuckets)
答案 0 :(得分:1)
警告的目的是告诉您某些操作在组件卸载后正在发生,并且该工作的结果将被丢弃。
解决方案不是尝试使用减速器解决它;解决方案是通过从 useEffect 返回回调来取消正在发生的任何事情。例如:
useEffect(() => {
const ctrl = new AbortController();
fetchExternalResource(ctrl.signal);
return () => {
ctrl.abort();
}
}, []);
使用标志来确定组件是否已安装(即使用减速器)来确定更新状态是否缺少警告点。
如果这实际上不是问题,也可以保留警告。它只是在那里挑剔并告诉您,嘿,您可能想要清理它。但这不是错误。
在您的情况下,如果您使用 fetch,我会修改您的代码,以便分派操作的函数可以采用 AbortSignal
来取消其操作。如果您不使用 fetch,则您无能为力,您应该忽略此警告。没什么大不了的。
看起来您正在使用 Axios 来处理您的请求。 Axios 支持类似于中止信号的机制 - 这应该可以解决问题。
import { CancelToken } from 'axios';
const getAllDemoBuckets = async (dispatch, cancelToken) => {
try {
const response = await axiosInstance.get('/demo/all', { cancelToken });
dispatch({ type: 'FETCH_SUCCESS', payload: response.data });
} catch (err) {
if ('isCancel' in err && err.isCancel()) {
return;
}
dispatch({ type: 'FETCH_ERROR' });
}
}
const MyComponent = () => {
useEffect(() => {
const source = CancelToken.source();
getAllDemoBuckets(dispatch, source.token);
return () => {
source.cancel();
};
}, []);
}