为啥即使组件的父标签标记为提供者,useContext 在组件中仍返回 null?

Posted

技术标签:

【中文标题】为啥即使组件的父标签标记为提供者,useContext 在组件中仍返回 null?【英文标题】:Why is useContext returning null in a component even though its parent tag is marked as the Provider?为什么即使组件的父标签标记为提供者,useContext 在组件中仍返回 null? 【发布时间】:2020-12-01 19:12:19 【问题描述】:

在过去的几个小时里,我一直在尝试使用 react-hooks 和 react-context 在我的子反应组件中访问用户状态,但我无法弄清楚。在此站点上发布的其他几个相关问题中,useContext 返回 null/undefined,因为使用它的组件未包含在标记为 Provider 的标签中。

在这里,我已经这样做了,但它仍然无法正常工作。当我记录 useContext(AuthContext) 的值时,它返回 null,但是当我记录分配给 AuthContext.Provider 的对象时,它会显示用户数据。非常感谢您的帮助。

App.js

import * as React from 'react';
import  Text, Button, View  from 'react-native';
import  NavigationContainer  from '@react-navigation/native';
import  createStackNavigator  from '@react-navigation/stack';
import  createBottomTabNavigator  from '@react-navigation/bottom-tabs';

// import firebase
import firebase from './firebase.js';

console.log(firebase)
const db = firebase.database();

var isSignedIn = true;
var testing = true

import AuthNavigator from './src/navigation/AuthNavigator'

export default function App() 
  return <AuthNavigator />

AuthNavigator.js

import firebase from './../../firebase.js';
// import auth from '@react-native-firebase/auth'
import SignInStack from './SignInStack'
import SignOutStack from './SignOutStack'
import TestScreen from './TestScreen'

export const AuthContext = createContext(null)

export default function AuthNavigator() 
    const [initializing, setInitializing] = useState(true)
    const [user, setUser] = useState(null)
  
    // Handle user state changes
    function onAuthStateChanged(result) 
      setUser(result)
      console.log(result);
      if (initializing) setInitializing(false)
    
  
    useEffect(() => 
      const authSubscriber = firebase.auth().onAuthStateChanged(onAuthStateChanged)
  console.log("getting here...")
      // unsubscribe on unmount
      return authSubscriber
    , [])
  
    if (initializing) 
      return null
    
  console.log('Hello World')
  console.log(user)
    return !user ? (
      <AuthContext.Provider value=user>
        <SignInStack />
      </AuthContext.Provider>
    ) : (
    <AuthContext.Provider value=user>
      <TestScreen/>
      </AuthContext.Provider>
    )
  

TestScreen.js

import * as React from 'react';
import  Text, View  from 'react-native';
import  NavigationContainer  from '@react-navigation/native';
import  createBottomTabNavigator  from '@react-navigation/bottom-tabs';

import  useContext  from 'react'
import  AuthContext  from './../navigation/authnavigator.js'

export default function TestScreen() 
    console.log(useContext(AuthContext))
  return (
    <View style= flex: 1, justifyContent: 'center', alignItems: 'center' >
      <Text>Likes You</Text>
    </View>
  );

【问题讨论】:

如果你没有将 react 钩子放在控制台日志中怎么办? 我看到你还没有导入 createContext ?? 如果我将 useContext(AuthContext) 分配给一个局部变量然后记录它,它仍然返回 null。 我没有在TestScreen.js中导入,但我只需要使用它,而不是在那个文件中创建它。 user 的初始值为null,这是您在上下文TestScreen 中看到的值吗?登录后,firebase auth 会选择它并调用onAuthStateChanged 回调并更新状态吗? 【参考方案1】:
    return !user ? (
      <AuthContext.Provider value=user>
        <SignInStack />
      </AuthContext.Provider>
    ) : (
    <AuthContext.Provider value=user>
      <TestScreen/>
      </AuthContext.Provider>
    )
  

这部分对我来说似乎有问题,因为您要创建两个单独的 AuthContext.Providers。

你应该做类似的事情

    return
      <AuthContext.Provider value=user>
         !user? <SignInStack />:
      <TestScreen/>
      </AuthContext.Provider>  
  

相反。或者你可能想从你自己的代码中重新设计一些基本的登录策略。

【讨论】:

【参考方案2】:

您似乎没有从 React namespace 调用 useContext

将您的代码更新为此 -

React.useContext(AuthContext)

而不是这个 -

useContext(AuthContext)

为了更好的衡量,也请更改此设置。

export const AuthContext = React.createContext(null)

【讨论】:

以上是关于为啥即使组件的父标签标记为提供者,useContext 在组件中仍返回 null?的主要内容,如果未能解决你的问题,请参考以下文章

为啥不更新我在子组件中传递的父组件中的值并更新使用自定义事件 $emit Vue 3?

为啥 git mergetool 显示没有冲突,即使合并后文件中存在冲突标记?

React/CSS:为啥我的 <p> 标签在移动设备上移动它的父 <div>?

如何访问嵌套 JSP 标记文件中的父属性?

为啥反应组件需要刷新才能加载其内容,即使在成功登录后也是如此?

如何在 react.js 的父组件中检测子渲染