使用createContext的 React初始值而不是提供的值



我在我的应用程序中创建了一个布尔值isDark的上下文。布尔值isDark是用useState创建的,我提供了这个布尔值和一个函数来将布尔值更改为ThemeContext,以便在组件树中进一步访问它。

在下面,我创建了ThemeContext,布尔值初始化为false,并在控制台中创建了一个函数,该函数仅警告正在使用初始值:

//ThemeContext.tsx
export type ContextType = {
isDark: boolean
toggleTheme: () => void
}
const ThemeContext = createContext<ContextType>({
isDark: false,
toggleTheme: () => console.warn('Still using initial value'),
})
export const useTheme = () => useContext(ThemeContext)
export default ThemeContext

这里我提供了主题和功能,通过toggleTheme函数来改变它:

//CustomThemeProvider.tsx
export const CustomThemeProvider: React.FC = ({ children }) => {
const [isDark, setDark] = useState(false)
const toggleTheme = () => {
console.log('Change theme')
setDark(!isDark)
}
const providerTheme = useMemo(
() => ({ isDark, toggleTheme }),
[isDark, toggleTheme],
)
return (
<ThemeProvider theme={isDark ? darkTheme : lightTheme}>
<ThemeContext.Provider value={providerTheme}>
{children}
</ThemeContext.Provider>
</ThemeProvider>
)
}

我现在想访问布尔值和toggleTheme函数,并通过我在开始时创建的自定义钩子(useTheme)来实现,它只使用useContext:

//App.tsx
export default function App() {
const { isDark, toggleTheme } = useTheme()
return (
<CustomThemeProvider>
<Box flex={1} justifyContent="center">
<Paper title="Test Title">
<Switch onValueChange={toggleTheme} value={isDark} />
</Box>
</CustomThemeProvider>
)
}

当我现在尝试用Switch组件(React Native)切换主题时,我得到控制台警告,我的初始函数正在被调用。这意味着我的toggleTheme函数仍然是初始函数() => console.warn('Still using initial value'),即使我提供了一个新函数,应该用我的ThemeContext.Provider改变isDark布尔值。
为什么我的初始函数仍然被交换机调用,而不是我提供的一个来改变主题?

您的useTheme()正在从默认状态获取值,因为在组件树中没有找到它上面的Provider(它在同一级别)。

只需用CustomThemeProvider(或更高级别)包装您的应用程序:

ReactDOM.render(
<CustomThemeProvider>
<App />
</CustomThemeProvider>,
document.getElementById('root')
);

也要小心setDark(!isDark),你应该实现它获得以前的状态setDark(state => !state),因为设置状态被推迟到重新渲染。

工作Stackblitz

顺便问一下,<ThemeProvider theme={isDark ? darkTheme : lightTheme}>,这行是不是打错了?如果您试图将上下文分成两部分(值和分派,这是一个好主意),我会这样做:
const ThemeContext = createContext({
isDark: false
});
export const useTheme = () => useContext(ThemeContext);
export default ThemeContext;
const ToggleThemeContext = createContext({
toggleTheme: () => console.warn('Still using initial value')
});
export const useToggleTheme = () => useContext(ToggleThemeContext);
export default ToggleThemeContext;
//CustomThemeProvider.tsx
export const CustomThemeProvider = ({ children }) => {
const [isDark, setDark] = useState(false);
const memoToggleTheme = useCallback(() => setDark(state => !state), [
setDark
]);
return (
<ToggleThemeContext.Provider value={memoToggleTheme}>
<ThemeContext.Provider value={isDark}>{children}</ThemeContext.Provider>
</ToggleThemeContext.Provider>
);
};

工作Stackblitz记忆的组件调度的动作,否则它将被重新呈现由theme组件当CC_22的变化。

通过这样做,只有使用该值的组件才会被重新渲染。

让我给你链接一篇我昨天写的关于React Context的文章,包括优化React Context, All in One

最新更新