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

Pat*_*nny 3 reactjs ionic-framework react-hooks ionic-react use-reducer

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

我按照这个教程进行了操作。

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

当我添加语句来检查上下文提供程序中的重新渲染时,我发现调用console.loga 时它也不会重新渲染。dispatch

上下文似乎是在本地更新,而不是全局更新。这个答案中有一条评论:

您正在使用减速器正确更新状态,但它只会更新本地组件状态,而不是全局上下文状态。

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

这是一些代码:

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>
  );
};
Run Code Online (Sandbox Code Playgroud)

我如何更新上下文

const { countState, countDispatch } = useContext(CountContext);
countDispatch({ type: 'add1' });
Run Code Online (Sandbox Code Playgroud)

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;
Run Code Online (Sandbox Code Playgroud)

路由器.tsx

<CountContextProvider>
  <IonReactRouter>
    <AppTabBar>
      <IonRouterOutlet>
        <Route exact path={myPageRoute}>
          <MyPage />
        </Route>
        <Route>
          <PageError404 />
        </Route>
      </IonRouterOutlet>
    </AppTabBar>
  </IonReactRouter>
</CountContextProvider>
Run Code Online (Sandbox Code Playgroud)

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>
  );
};
Run Code Online (Sandbox Code Playgroud)

在这种情况下,当 中的上下文更新时<MyPage><TabBarCounter>内部的<AppTabBar>不会更新,但<TabBarCounter>内部<MyPage>会更新。

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

Ait*_*war 5

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

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

要修复此问题,请使用扩展运算符使用先前状态的键和更新的属性创建新对象total

case 'add1': {
  return {
    ...countObject,
    total: countObject.total + 1,
  };
}
Run Code Online (Sandbox Code Playgroud)