React Context调用useContext返回undefined问题求助
你遇到的问题核心在于组件调用useStep的时机不在StepProvider的包裹范围内。React Context的传递是基于组件树的——只有当调用useContext的组件位于对应的Provider组件的子树中时,才能获取到Context的值。
看你的OnboardingScreen代码:
const OnboardingScreen = () => { // 这里调用useStep的时候,StepProvider还没被渲染! const {state:{step}} = useStep() return ( <StepProvider> {/* ... 子组件内容 ... */} </StepProvider> ) }
当OnboardingScreen组件开始渲染时,首先会执行顶层的useStep()调用,这时候StepProvider还没有被挂载到组件树上,当前组件不在Provider的覆盖范围内,所以useContext(StepContext)返回undefined,触发了你设置的错误。
有两种常见的修复方式,你可以根据自己的代码结构选择:
方案1:将StepProvider提升到父组件
把StepProvider移到OnboardingScreen的上层组件(比如导航配置组件、App组件或者它的直接父组件),让OnboardingScreen本身处于Provider的包裹中:
比如在导航配置里:
// 假设这是你的导航配置文件 import { StepProvider } from './StepContext' import OnboardingScreen from './OnboardingScreen' const AppNavigator = () => { return ( <StepProvider> <Stack.Navigator> <Stack.Screen name="Onboarding" component={OnboardingScreen} /> {/* 其他页面 */} </Stack.Navigator> </StepProvider> ) }
这样修改后,OnboardingScreen在渲染时就已经处于StepProvider的子树中,调用useStep()就能正常获取Context值了。
方案2:拆分组件,让useStep在Provider的子组件中调用
如果不想改动父组件结构,可以把OnboardingScreen中需要使用Context的部分拆成一个子组件,让这个子组件被StepProvider包裹:
修改后的OnboardingScreen代码:
import { BodyText, H3, H5, H4 } from '../../typography' import * as React from 'react' import { Box, Icon } from '../../components' import { useState } from 'react' import { StyleSheet, TouchableOpacity, View } from 'react-native' import { useNavigation } from '@react-navigation/native' import { useAuthContext } from '../../context/AuthProvider' import { Enum_Userspermissionsuser_Userrole } from '../../generated/graphql' import Start from './Start' import stepOne from './StepOne' import { StepProvider, useStep } from './StepContext' // 拆分子组件,这里面调用useStep const InnerOnboarding = () => { const {state:{step}} = useStep() const [stepper, setStepper] = useState([0, 1, 2, 3, 4, 5]) const { navigate } = useNavigation() const { user } = useAuthContext() return ( <Container px={5} justifyContent="flex-start" downbg hasNavbar={false}> <View style={{ flexDirection: 'row', justifyContent: 'space-evenly', marginTop:'12%'}}> {stepper.map((step, i) => ( <Box height={5} width={50} bg="b2gpeach" borderRadius={11} key={i} /> ))} </View> <Start /> {console.log(step)} </Container> ) } const OnboardingScreen = () => { return ( <StepProvider> <InnerOnboarding /> </StepProvider> ) } export default OnboardingScreen
这样InnerOnboarding作为StepProvider的直接子组件,在渲染时处于Context的覆盖范围内,调用useStep()就能正确获取到step值了。
React Context的工作机制是向下传递:Provider组件会为它的所有子组件(包括深层子组件)提供Context值。任何调用useContext的组件必须位于Provider的子树中,否则无法获取到Context值。你的自定义hookuseStep内部调用了useContext,所以必须遵守这个规则。
内容的提问来源于stack exchange,提问作者Jude Bobinihi

