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>

当我这样做时:

  1. 转到其他页面
  2. 增加计数(修改状态)
  3. 返回主页
  4. 增加计数(修改状态) ==> 转到控制台,出现错误
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 进行那个小改动。但我不希望它很快得到解决,因为它似乎是一个只在开发中发生的问题。