Ionic React Overmind 无法对未安装的组件执行 React 状态更新
Ionic React Overmind Can't perform a React state update on an unmounted component
我使用 Overmind 与离子反应:
选项卡 1:
const { count } = useAppState()
const { increaseCount } = useActions()
return
<IonPage>
<IonContent>
<IonRouterLink routerLink='/tab1/page1'>1. Go to another page</IonRouterLink> // Go to page 1
<IonText><p>{count}</p></IonText>
<IonButton onClick={() => increaseCount()}>4. Increase again</IonButton>
</IonContent>
</IonPage>
第 2 页:
const { count } = useAppState()
const { increaseCount } = useActions()
return
<IonPage>
<IonContent>
<IonBackButton defaultHref="/" /> // Go back to tab 1
<IonText><p>{count}</p></IonText>
<IonButton onClick={() => increaseCount()}>4. Increase again</IonButton>
</IonContent>
</IonPage>
当我这样做时:
- 转到其他页面
- 增加计数(修改状态)
- 返回主页
- 增加计数(修改状态)
==> 转到控制台,出现错误
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.
我创建了这个最小复制代码:https://github.com/dopeshot/ionic-overmind-cant-perform-state-update
我还制作了一个关于该问题的短视频:https://www.youtube.com/watch?v=5w6r1_lxoS8
我该如何解决这个问题?
如果组件尚未安装,您需要不更新回调中的状态。
作为错误状态:
Error Warning: Can't perform a React state update on an unmounted
component.
解决方案
在useActions
(或useEffect
中声明让isMounted = true
,不建议使用useAction
,并且不再真正支持,你可以阅读redux's creator comment on this ),一旦卸载组件,它将在清理回调中更改。在状态更新之前,您现在有条件地检查此变量:
useEffect(() => {
let isMounted = true; // note mutable flag
someAsyncOperation().then(data => {
if (isMounted) setState(data); // add conditional check
})
return () => { isMounted = false }; // cleanup toggles value, if unmounted
}, []); // adjust dependencies to your needs
更彻底的解决方案:自定义useAsync
Hook
我们可以将所有样板封装到一个自定义 Hook 中,如果组件卸载或依赖值之前发生更改,它会自动中止异步函数:
function useAsync(asyncFn, onSuccess) {
useEffect(() => {
let isActive = true;
asyncFn().then(data => {
if (isActive) onSuccess(data);
});
return () => { isActive = false };
}, [asyncFn, onSuccess]);
}
这个问题是 overmind-react 库中的一个错误。如果您查看源代码,您会看到当组件卸载时它们不会将 mountedRef.current
设置为 false,因此当状态更改时它会尝试重新呈现已卸载的组件。它应该就在这里
https://github.com/cerebral/overmind/blob/cb095ffa0cd49504fed6bbc99054d89ba9b92ea3/packages/overmind-react/src/index.ts#L139
您可以克隆该存储库,将以下更改添加到代码中,并将依赖项指向您在 git 存储库中的版本(或发布您自己的包)
return () => {
mountedRef.current = false;
overmind.eventHub.emitAsync(EventType.COMPONENT_REMOVE, {
最好是打开一个 GitHub 问题,如果可能的话,打开 PR 进行那个小改动。但我不希望它很快得到解决,因为它似乎是一个只在开发中发生的问题。
我使用 Overmind 与离子反应:
选项卡 1:
const { count } = useAppState()
const { increaseCount } = useActions()
return
<IonPage>
<IonContent>
<IonRouterLink routerLink='/tab1/page1'>1. Go to another page</IonRouterLink> // Go to page 1
<IonText><p>{count}</p></IonText>
<IonButton onClick={() => increaseCount()}>4. Increase again</IonButton>
</IonContent>
</IonPage>
第 2 页:
const { count } = useAppState()
const { increaseCount } = useActions()
return
<IonPage>
<IonContent>
<IonBackButton defaultHref="/" /> // Go back to tab 1
<IonText><p>{count}</p></IonText>
<IonButton onClick={() => increaseCount()}>4. Increase again</IonButton>
</IonContent>
</IonPage>
当我这样做时:
- 转到其他页面
- 增加计数(修改状态)
- 返回主页
- 增加计数(修改状态) ==> 转到控制台,出现错误
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.
我创建了这个最小复制代码:https://github.com/dopeshot/ionic-overmind-cant-perform-state-update
我还制作了一个关于该问题的短视频:https://www.youtube.com/watch?v=5w6r1_lxoS8
我该如何解决这个问题?
如果组件尚未安装,您需要不更新回调中的状态。
作为错误状态:
Error Warning: Can't perform a React state update on an unmounted component.
解决方案
在useActions
(或useEffect
中声明让isMounted = true
,不建议使用useAction
,并且不再真正支持,你可以阅读redux's creator comment on this ),一旦卸载组件,它将在清理回调中更改。在状态更新之前,您现在有条件地检查此变量:
useEffect(() => {
let isMounted = true; // note mutable flag
someAsyncOperation().then(data => {
if (isMounted) setState(data); // add conditional check
})
return () => { isMounted = false }; // cleanup toggles value, if unmounted
}, []); // adjust dependencies to your needs
更彻底的解决方案:自定义useAsync
Hook
我们可以将所有样板封装到一个自定义 Hook 中,如果组件卸载或依赖值之前发生更改,它会自动中止异步函数:
function useAsync(asyncFn, onSuccess) {
useEffect(() => {
let isActive = true;
asyncFn().then(data => {
if (isActive) onSuccess(data);
});
return () => { isActive = false };
}, [asyncFn, onSuccess]);
}
这个问题是 overmind-react 库中的一个错误。如果您查看源代码,您会看到当组件卸载时它们不会将 mountedRef.current
设置为 false,因此当状态更改时它会尝试重新呈现已卸载的组件。它应该就在这里
https://github.com/cerebral/overmind/blob/cb095ffa0cd49504fed6bbc99054d89ba9b92ea3/packages/overmind-react/src/index.ts#L139
您可以克隆该存储库,将以下更改添加到代码中,并将依赖项指向您在 git 存储库中的版本(或发布您自己的包)
return () => {
mountedRef.current = false;
overmind.eventHub.emitAsync(EventType.COMPONENT_REMOVE, {
最好是打开一个 GitHub 问题,如果可能的话,打开 PR 进行那个小改动。但我不希望它很快得到解决,因为它似乎是一个只在开发中发生的问题。