上下文消费者中的 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,
};
}
我向我的 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,
};
}