简体   繁体   English

使用 useContext 返回 undefined 的 React Context

[英]React Context returning undefined with useContext

I have context set up within my app.我在我的应用程序中设置了上下文。 not at the root and for some reason it returns undefined.不在根部,由于某种原因它返回未定义。

I have this as the index where I create the context:我将其作为创建上下文的索引:

import React, { createContext, useContext, useReducer } from 'react'

type Action = { type: 'next' } | { type: 'back' }
type Dispatch = (action: Action) => void
type State = { step: number }
type StepProviderProps = { children: React.ReactNode }

const StepContext = createContext<{ state: State; dispatch: Dispatch } | undefined>(undefined)
const stepReducer = (state: State, action: Action) => {
  switch (action.type) {
    case 'next': {
      return { step: state.step + 1 }
    }
    case 'back': {
      return { step: state.step - 1 }
    }
    default: {
      throw new Error(`Unhandled action type`)
    }
  }
}

const StepProvider = ({ children }: StepProviderProps) => {
  const [state, dispatch] = useReducer(stepReducer, { step: 0 })
  const value = { state, dispatch }
  return <StepContext.Provider value={value}>{children}</StepContext.Provider>
}

const useStep = () => {
  const context = useContext(StepContext)
  if (context === undefined) {
    throw new Error('useStep should be used within StepProvider')
  } else {
    return context
  }
}

export { StepProvider, useStep }

then I import it here:然后我在这里导入它:

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'

const OnboardingScreen = () => {
  const [stepper, setStepper] = useState([0, 1, 2, 3, 4, 5])

  const { navigate } = useNavigation()
  const { user } = useAuthContext()
  const {state:{step}} = useStep()
 

  return (
    <StepProvider>
      <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>
      </StepProvider>
  )
}



export default OnboardingScreen

I think I should be able to get console log of the context but I get the context undefined error I set to check if context is defined.我想我应该能够获取上下文的控制台日志,但我得到了上下文未定义的错误,我设置为检查上下文是否已定义。

You are calling useStep at the same level as the StepProvider .您在与StepProvider useStep

You can't use the value from the context in the same component where you've wrapped it.您不能在包装它的同一组件中使用上下文中的值。

You need to wrap StepProvider in the parent component then use it:您需要将StepProvider包装在父组件中,然后使用它:

import { StepProvider} from './StepContext'

const ParenComponent = () => {
 <StepProvider>
   <OnboardingScreen/>
 </StepProvider>
}
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 { useStep } from './StepContext'

const OnboardingScreen = () => {
  const [stepper, setStepper] = useState([0, 1, 2, 3, 4, 5])

  const { navigate } = useNavigation()
  const { user } = useAuthContext()
  const {state:{step}} = useStep()
 

  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>
  )
}

export default OnboardingScreen

You must use useContext within components wrapped with provider:您必须在提供程序包装的组件中使用useContext

<StepProvider>
  <OnboardingScreen />
</StepProvider>

So, you could do something like this:所以,你可以这样做:

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'

const OnboardingScreen = () => {
  const [stepper, setStepper] = useState([0, 1, 2, 3, 4, 5])

  const { navigate } = useNavigation()
  const { user } = useAuthContext()
  const {state:{step}} = useStep()
 
  // Provider removed
  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>
  )
}

// Export wrapped with provider
export default () => (
  <StepProvider>
    <OnboardingScreen />
  </StepProvider>
)

what worked for me was declaring the types.对我有用的是声明类型。 Make use of the following logic:使用以下逻辑:

My AuthContext.tsx我的 AuthContext.tsx

...
1. interface contextValueTypes {
    login: Function,
    logout: Function,
    isLoading: boolean,
    userToken: string,
}

2. export const AuthContext = createContext<contextValueTypes>({
    login: Function,
    logout: Function,
    isLoading: false,
    userToken: "",
});
...

And in my App.js在我的 App.js 中

const App = () => {
  const { isLoading, userToken } = useContext(AuthContext);
  return (
    <AuthProvider>
        {userToken == null ? <AppStack /> : <AuthStack />}
    </AuthProvider>
  );
}

I hope this helps ya我希望这对你有帮助

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM