注销反应应用程序会导致主屏幕出现空指针

Posted

技术标签:

【中文标题】注销反应应用程序会导致主屏幕出现空指针【英文标题】:Logging out of react app results in nullpointer in homescreen 【发布时间】:2021-02-21 15:16:04 【问题描述】:

我正在开发一个带有登录页面的反应应用程序。当用户成功登录时,后端会返回一个用户对象 (JSON),其中包含一些用户属性(id、用户名、...)以及 JWT 令牌。用户对象存储在 AsyncStorage 中(因此用户只需登录一次)。

try 
   await AsyncStorage.setItem('authUser', JSON.stringify(data));
 catch (e) 
   console.log(e.message);


dispatch( type: 'SIGN_IN', authUser:data);

状态:

const [state, dispatch] = React.useReducer(

        (prevState, action) => 
          switch (action.type) 
            case 'RESTORE_TOKEN':
              return 
                ...prevState,
                authUser: action.authUser,
                isLoading: false,
              ;
            case 'SIGN_IN':
              return 
                ...prevState,
                isSignout: false,
                authUser: action.authUser,
              ;
            case 'SIGN_OUT':
              return 
                ...prevState,
                isSignout: true,
                authUser: null,
              ;
          
        ,
        
          isLoading: true,
          isSignout: false,
          authUser: "",
        
    );

我第二次从 AsyncStorage 检索用户对象并将其传递给状态。

try 
   authUser = await AsyncStorage.getItem('authUser');
 catch (e) 
   console.log(e.message);

dispatch( type: 'RESTORE_TOKEN', authUser: JSON.parse(authUser) );

我使用 UserContext 将authUser 传递到我的欢迎屏幕:

<AuthContext.Provider value=authContext>
   <UserContext.Provider value=authUser: state.authUser >
      <NavigationContainer>
         <RootStack.Navigator mode="modal" headerMode="none">
            state.isLoading ? (
               <RootStack.Screen name="Splash" component=SplashScreen />
            ) : state.authUser == null ? (
               <RootStack.Screen name="Login" component=AuthenticationStackScreen />
            ) : (
               <RootStack.Screen name="Home" component=HomeScreen />
            )
         </RootStack.Navigator>
      </NavigationContainer>
   </UserContext.Provider>
</AuthContext.Provider>

在我的主屏幕中,我打印了一条包含用户名和signOut 按钮的欢迎消息:

function HomeScreen(props) 

    const  signOut  = React.useContext(AuthContext);
    const  authUser  = React.useContext(UserContext);

    return (

        <View style= flex:1, alignItems: 'center', justifyContent: 'center', backgroundColor:'cyan' >

        <Text>Hallo authUser.username</Text>
            <Button title="Log out" onPress=signOut />
            <Text>HomeScreen </Text>
        </View>

    );

当用户登录或已经登录时,主屏幕会以正确的用户名正确显示。单击注销按钮时会出现问题。 authContext 中的 signOut 方法被调用,该方法注销用户并从 AsyncStorage 中删除对象:

signOut: async () => 

   try 
      await AsyncStorage.removeItem('authUser');
    catch (e) 
      console.log(e.message);
   
   dispatch( type: 'SIGN_OUT' )

问题: 状态更改为SIGN_OUT,这让我回到了登录页面。但是由于我已经清除了用户对象,所以欢迎通知会引发错误,因为 authUser.usernamenull

TypeError: null is not an object (evaluating 'authUser.username')

我没想到在单击退出按钮时会重新呈现 WelcomeScreen。我是否弄乱了我的应用程序的结构,或者为什么会这样?任何有关如何解决此问题的帮助将不胜感激。提前致谢!

【问题讨论】:

只有当 authUser 可用时才能通过访问用户名来处理它authUser?.username,它可能会重新呈现,因为您有两个不同的上下文提供程序 嗨,Guruparan,有没有办法我也可以在 authContext 中传递用户对象?所以我只能使用一个上下文? 上下文可以包含任何对象,所以我确信您可以将所有这些信息放入一个对象中并将其放置在上下文中以便它可能 【参考方案1】:

根据 React documentation useContext 将始终在上下文值更改时重新渲染,因此这就是再次调用 HomeScreen 的原因。

您需要修复的另一件事是 authUser 初始状态等于 authUser signOut 状态:

const [state, dispatch] = React.useReducer(

        (prevState, action) => 
          switch (action.type) 
            case 'RESTORE_TOKEN':
              return 
                ...prevState,
                authUser: action.authUser,
                isLoading: false,
              ;
            case 'SIGN_IN':
              return 
                ...prevState,
                isSignout: false,
                authUser: action.authUser,
              ;
            case 'SIGN_OUT':
              return 
                ...prevState,
                isSignout: true,
                authUser: null,
              ;
          
        ,
        
          isLoading: true,
          isSignout: false,
          authUser: "", //MAKE THIS THE SAME AS SIGN_OUT (null)
        
    );

【讨论】:

嗨,Michael,我已将 authUser 的默认值更改为 null,感谢您的建议!我被重定向到登录,而不是主屏幕,所以看起来没问题。我已经检查了 authUser 并且它肯定是空的,所以我真的不知道为什么 HomeScreen 会重新渲染并给出这个错误。使用两个上下文可能与我有关吗?我也尝试将用户对象添加到 authContext,但我没有让它工作。这甚至可能吗?感谢您的帮助! @TimCreemers 我编辑了答案,提到 useContext 会触发重新渲染。 嗨迈克尔,感谢您的支持。据我所知,我没有在我的 signOut 功能中使用 useContext 吗?如果我问愚蠢的问题,我很抱歉,上下文对我来说有点难以理解 @TimCreemers 您正在 HomeScreen 中使用 useContext。因此,此屏幕将在上下文值更改时重新呈现。

以上是关于注销反应应用程序会导致主屏幕出现空指针的主要内容,如果未能解决你的问题,请参考以下文章

实例变量访问(通过 self)导致空指针取消引用

unity_实用小技巧(空指针错误)

unity_实用小技巧(空指针错误)

空指针异常 - findViewById()

AsyncStorage 在本机反应中隐藏登录屏幕

数据的校验和空指针