繁体   English   中英

使用 useContext 返回 undefined 的 React Context

[英]React Context returning undefined with useContext

我在我的应用程序中设置了上下文。 不在根部,由于某种原因它返回未定义。

我将其作为创建上下文的索引:

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 }

然后我在这里导入它:

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

我想我应该能够获取上下文的控制台日志,但我得到了上下文未定义的错误,我设置为检查上下文是否已定义。

您在与StepProvider useStep

您不能在包装它的同一组件中使用上下文中的值。

您需要将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

您必须在提供程序包装的组件中使用useContext

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

对我有用的是声明类型。 使用以下逻辑:

我的 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: "",
});
...

在我的 App.js 中

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

我希望这对你有帮助

暂无
暂无

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

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