使用React ContextAPI+useState获取themeMode返回undefined问题求助
你在App组件的顶层直接调用了useToggleTheme(),但此时App组件并没有被ToggleThemeContextProvider包裹——React Context的作用域仅限于Provider所包裹的子组件树,Provider外部的组件只能获取到createContext时传入的默认值。你这里用{} as ITheme强制转换了一个空对象作为默认值,所以themeMode自然是undefined。
把需要使用themeMode的逻辑移到ToggleThemeContextProvider内部的组件中,比如抽离一个内部组件:
export default function App() { return ( <HeaderContextProvider> <ToggleThemeContextProvider> <AppContent /> </ToggleThemeContextProvider> </HeaderContextProvider> ) } // 单独抽离内部组件,确保在ToggleThemeContextProvider作用域内 function AppContent() { const { themeMode } = useToggleTheme() console.log(themeMode) // 现在能正常获取到主题值了 return ( <ThemeProvider theme={themeMode}> <SafeAreaProvider> {fontsLoaded ? <Routes /> : <Loading />} <StatusBar style="auto" backgroundColor="transparent" translucent /> </SafeAreaProvider> </ThemeProvider> ) }
你之前把initialValues传入createContext后setThemeMode失效,是因为默认值里的setThemeMode是个空函数() => null——当组件不在Provider内部时,拿到的是这个默认的空函数,自然无法触发状态更新。只有在Provider包裹的子组件中,才能获取到Provider提供的真实setThemeMode方法。
可以在自定义hook里添加校验,防止在Provider外部调用时出现隐性错误:
export function useToggleTheme(): ITheme { const context = useContext(ToggleThemeContext) if (!context) { throw new Error('useToggleTheme must be used within a ToggleThemeContextProvider') } return context }
这样错误使用时会抛出明确的提示,更容易排查问题。
和当前主题Context的问题完全一致:调用useXXX hook的组件不在对应的Provider作用域内,所以拿到的是默认值(如果默认值未正确初始化就是undefined);而能调用setXXX更新状态的组件,一定是在Provider内部的,所以状态能正常更新,但外部组件还是拿不到最新值。
内容的提问来源于stack exchange,提问作者Vinicius Celestino

