[英]React Context Consumer not changing reactively or rerendering
我有一個奇怪的情況,狀態變量在一個組件中成功更新,但在另一個組件中沒有。 我成功地改變了state
,因為我可以看到它反映在我觸發dispatch
的組件中。 但是在包裝在同一個Provider
中的另一個組件中,我看不到任何變化。
其他 Stack Overflow 答案似乎主要建議不要直接改變 state ,但在這里我沒有這樣做 - 我正在調度一個操作來更新狀態,類似於您在 Redux 語法中看到的內容。
TeaSettingsContext.tsx
const TeaSettingsContext = createContext<{ state: State; dispatch: Dispatch } | undefined>(undefined);
const teaSettingsReducer = (state: State, action: Action) => {
switch (action.type) {
case TeaSettingsActions.ChooseTea: {
return { ...state, chosenTea: action.payload };
}
case TeaSettingsActions.ChangeStrength: {
return { ...state, desiredStrength: action.payload };
}
default: {
throw new Error(`Unhandled action type: ${action.type}`);
}
}
};
export function TeaSettingsProvider({
children,
}: TeaSettingsProviderProps): Context {
const [state, dispatch] = useReducer(teaSettingsReducer, {
chosenTea: {},
desiredStrength: 0.5,
});
return (
<TeaSettingsContext.Provider value={{ state, dispatch }}>
{children}
</TeaSettingsContext.Provider>
);
}
export const useTeaSettingsContext = (): TeaSettingsContext => {
const context = useContext(TeaSettingsContext);
if (context === undefined) {
return;
}
return context;
};
這是“成功”的組成部分:
主頁.tsx
<TeaSettingsProvider>
<StrengthSlider />
</TeaSettingsProvider>
強度滑塊.tsx
export default function StrengthSlider(): ReactNode {
const { state, dispatch } = useTeaSettingsContext();
console.log(state.desiredStrength) // logs the increment on each press.
const incrementStrength = () => {
dispatch({
payload: state.desiredStrength + 0.1,
type: "change-strength",
});
};
return (
<Box position="relative" w="100%">
<Button title="Press" onPress={incrementStrength} />
<Text>{state.desiredStrength}</Text>
</Box>
);
}
...並且不成功的重新渲染發生在此組件中:
茶頁.tsx
const Component = () => {
if (type === "tea") {
return data.map((teaObj) => (
<TeaCard id={teaObj.id} teaData={teaObj.data} key={teaObj.id} />
));
}
};
return (
<TeaSettingsProvider>
<Component />
</TeaSettingsProvider>
);
茶卡.tsx
export function TeaCard({ id, teaData }: TeaCardProps): ReactNode {
const { state, dispatch } = useTeaSettingsContext();
console.log(state.desiredStrength); // this always logs the starting value of 0.5 and doesn't log each time I press the button above.
// ...
}
僅供參考:我的代碼基於 Kent C Dodds 的文章: https : //kentcdodds.com/blog/how-to-use-react-context-effectively
我認為您誤解了上下文的工作原理。
基本上(如反應文檔所建議的那樣):
每個 Context 對象都帶有一個 Provider React 組件,該組件允許消費組件訂閱上下文更改。
Provider 組件接受要傳遞給作為此 Provider 后代的消費組件的 value prop。 一個提供者可以連接到多個消費者。 提供者可以嵌套以覆蓋樹中更深層次的值。
每當 Provider 的 value 屬性發生變化時,所有作為 Provider 后代的消費者都會重新渲染。 從 Provider 到其后代消費者(包括 .contextType 和 useContext)的傳播不受 shouldComponentUpdate 方法的影響,因此即使祖先組件跳過更新,消費者也會更新。
簡而言之,當您創建一個具有值的提供者時,您可以從多個消費者(需要是該提供者的孩子)訪問該信息。 到現在為止還挺好。
除了: Home.tsx
和TeaPage.tsx
都初始化了一個不同的上下文實例(所以每個實例都有自己的提供者)。 為了解決這個問題,您應該只在Home
和TeaPage
父組件中創建一個提供程序。
React 上下文不能作為 redux(你有一個可以從任何地方訪問的全局存儲)。 它讓您可以選擇為大組件(在子組件中使用)創建上下文(使用可重用數據)。
另請注意開頭引用的最后一段:基本上當上下文發生變化時,這會導致所有消費者重新渲染(有時可能會導致一些性能問題),因此請明智地使用它。 這是一篇關於此的簡短文章。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.