上下文消费者中的 useReducer 在某些位置更改后不会更新

useReducer in Context consumer does not update after change in some locations

我向我的 Ionic React 应用程序添加了一个包含 useReducer 挂钩的上下文。我看到了一些奇怪的行为:当我使用 dispatch 调用更新上下文值时,消费者组件将在页面上更新,但选项卡栏上完全相同的组件不会更新。

我关注了this tutorial

当我添加 console.log 语句来检查组件是否正在重新加载时,我看到即使上下文值已更改,放置在选项卡栏 (<TabBarCounter>) 中的组件也没有重新加载改变了。

当我添加 console.log 语句来检查我的上下文提供程序中的重新呈现时,我发现它在调用 dispatch 时也没有重新呈现。

似乎上下文是在本地而不是全局更新的。 this answer中有评论:

You are updating your state correctly using a reducer but it will only update local component state not the global context state.

这听起来很像我在这里遇到的问题。

这是一些代码:

MyContext.tsx

export const CountContext = React.createContext<any>({} as {
  countState: CountState,
  countDispatch: React.Dispatch<CountReducerActions>,
});

interface MyProps {
  children: JSX.Element,
}

const reducer = (countState: CountState, action: CountReducerActions) => {
  switch (action.type) {
    case 'add1': {
      countObject.total += 1;
      return countObject;
    }
    default: {
      throw new Error();
    }
  }
};

export const CountContextProvider: React.VFC<MyProps> = ({ children }: MyProps) => {
    const [countState, countDispatch] = useReducer(
    reducer,
    {
      total: 0,
    },
  );

  return (
    <CountContext.Provider value={{ countState, countDispatch }}>
      {children}
    </CountContext.Provider>
  );
};

我如何更新上下文

const { countState, countDispatch } = useContext(CountContext);
countDispatch({ type: 'add1' });

MyComponentThatDoesNotGetRerendered.tsx

import React, { useContext } from 'react';
import { IonBadge } from '@ionic/react';
import { CountContext } from '../../context/CountContext';

const TabBarCounter: React.VFC = () => {
  const [countState] = useContext(CountContext);
  return (
    <IonBadge>
      {countState.total}
    </IonBadge>
  );
};

export default TabBarCounter;

Router.tsx

<CountContextProvider>
  <IonReactRouter>
    <AppTabBar>
      <IonRouterOutlet>
        <Route exact path={myPageRoute}>
          <MyPage />
        </Route>
        <Route>
          <PageError404 />
        </Route>
      </IonRouterOutlet>
    </AppTabBar>
  </IonReactRouter>
</CountContextProvider>

AppTabBar.tsx

const AppTabBar: React.VFC<MyProps> = ({ children }: MyProps) => {
  const [userObject] = useContext(UserContext);
  return (
    <IonTabs>
      {children}
      <IonTabBar slot="bottom" id="appTabBar">
        <IonTabButton tab="tab-settings" href={routeTabSettings}>
          <IonLabel>Settings</IonLabel>
        </IonTabButton>
        <IonTabButton
          tab="tab-count"
          href={routeTabCount}
        >
          <TabBarReviewCounter />
          <IonLabel>Count</IonLabel>
        </IonTabButton>
      </IonTabBar>
    </IonTabs>
  );
};

在这种情况下,当 <MyPage> 中的上下文更新时,<AppTabBar> 中的 <TabBarCounter> 不会更新,但 <TabBarCounter> 中的 <TabBarCounter> 21=] 确实得到更新。

如何使用 useReducer() 正确更新上下文,以便在更新上下文值时更新该上下文的所有使用者?

看看你的减速器。您无需以不可变的方式修改状态,而只需在不创建新引用的情况下覆盖 属性,因此上下文值永远不会更新。

某些组件可能会 'see' 由于某些原因重新渲染时会发生此更改 - 本地状态更改,道具更改等。它们将到达上下文,查看提供的对象并查看新值。

要修复它,请使用扩展运算符使用先前状态的键创建新对象并更新 total 属性.

case 'add1': {
  return {
    ...countObject,
    total: countObject.total + 1,
  };
}