注销 React 应用程序会导致主屏幕出现空指针
Logging out of react app results in nullpointer in homescreen
我正在开发一个带有登录页面的 React 应用程序。当用户成功登录时,后端 returns 一个用户对象 (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.username}
是 null
:
TypeError: null is not an object (evaluating 'authUser.username')
我没想到在单击退出按钮时会重新呈现 WelcomeScreen。我搞砸了我的应用程序的结构,或者这是为什么?任何有关如何解决此问题的帮助将不胜感激。提前致谢!
根据 React documentation useContext 将始终 re-render 当上下文值更改时,这就是再次调用 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)
}
);
我正在开发一个带有登录页面的 React 应用程序。当用户成功登录时,后端 returns 一个用户对象 (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.username}
是 null
:
TypeError: null is not an object (evaluating 'authUser.username')
我没想到在单击退出按钮时会重新呈现 WelcomeScreen。我搞砸了我的应用程序的结构,或者这是为什么?任何有关如何解决此问题的帮助将不胜感激。提前致谢!
根据 React documentation useContext 将始终 re-render 当上下文值更改时,这就是再次调用 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)
}
);