javascript - 不应该渲染的 React Native Navigator 屏幕
问题描述
我在我的 react 本机应用程序上使用 React Navigation 并遵循其身份验证流程。
app.js 将根据称为 userProfile 的用户身份验证状态呈现身份验证屏幕或主屏幕。
userProfile 将通过称为 userContext 的 React 上下文从 App 组件传递给子组件,并且一些调度函数也将被称为 authContext 传递。
const App: () => React$Node = () => {
const [state, dispatch] = React.useReducer(
(prevState, action) => {
switch (action.type) {
case SIGN_IN:
return {
...prevState,
userProfile: action.userProfile,
};
case SIGN_OUT:
return {
...prevState,
userProfile: null,
};
}
},
{
isLoading: true,
userProfile: null,
}
)
React.useEffect(() => {
isMountedRef.current = true;
return () => (isMountedRef.current = false);
}, []);
const authContext = React.useMemo(
() => ({
signIn: async userProfile => {
try {
await AsyncStorage.setItem('userProfile', JSON.stringify(userProfile))
dispatch({ type: SIGN_IN, userProfile })
} catch (error) {
console.log(error)
}
},
signOut: async () => {
try {
await AsyncStorage.removeItem('userProfile');
dispatch({ type: SIGN_OUT })
} catch (error) {
console.log(error)
}
}
}),
[]
);
return (
<AuthContext.Provider value={{authContext, userContext: state.userProfile}}>
<NavigationContainer ref={navigationRef}>
<Stack.Navigator>
{console.log('app render: ', state.userProfile)}
{
state.userProfile == null ?
(<Stack.Screen name="AuthContainer" component={AuthContainer} options={{ headerShown: false }} />) :
(<Stack.Screen name="MainContainer" component={MainContainer} options={{ headerShown: false }} />)
}
</Stack.Navigator>
</NavigationContainer>
</AuthContext.Provider>
);
};
在主屏幕下或上面代码中 MainContainer 下的嵌套子组件 ProfileScreen 之一中,我正在尝试使用 userContext 在屏幕上显示用户信息,并且注销按钮正在使用调度注销功能来更新用户身份验证在 App 组件中将 state 设置为 null。
function ProfileScreen() {
const { authContext, userContext } = React.useContext(AuthContext)
console.log('profile render: ', userContext)
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Hello {userContext.username}!</Text>
<Text>Profile Screen</Text>
<Button
title="Sign Out"
onPress={() => authContext.signOut()}
/>
</View>
);
}
export default ProfileScreen;
发送注销功能后,我希望应用程序导航到身份验证屏幕 AuthContainer 以要求用户再次登录,因为此时我在 App 组件中的 userProfile 状态应该为空。但是,App 组件仍在尝试呈现抛出错误 userContext is null 的 ProfileScreen。
从我的日志中,我在 ProfileScreen 中发送注销功能后,它显示
app render: null ---> App re-render
profile render: null ---> profileScreen re-render
profile render: null ---> profileScreen re-render
auth container ---> finally start rendering Auth Screen
然后立即抛出 userContext is null 错误
任何人都可以帮助我理解为什么 App 组件在 userProfile 状态为空时尝试渲染 profileScreen 吗?为什么 profileScreen 会重新渲染两次?
非常感谢你
解决方案
看起来您的条件Stack.Screen
和 ProfileScreen 都依赖于userProfile
状态。因为那个状态是异步更新的(就像 React 中的所有东西一样),它让我相信竞争条件导致了你的问题。
即,您调度操作以更新您的商店,但 ProfileScreenuserContext.username
在受保护容器接收更新之前接收到更新state.userProfile == null ? <Screen1 /> : <Screen2 />
。
IMO 使用来自外部来源的数据的组件必须始终保护自己免受缺失值的影响。尤其是当您明确取消该状态时。
在你的情况下,我只会写userContext?.username
。或者userContext ? <Text>{`Hello ${userContext.username}!`}</Text> : null
推荐阅读
- windows - 在路径中引发非法字符
- java - 在 Slf4j 运行时添加和更改全局 ID
- powershell - 有没有办法删除声称正在使用的文件夹?
- objective-c - 如何在 appDelegate Objective-C 中呈现弹出视图并关闭
- sql - 是否可以将数据从 ADLS 加载到 DBX 中的 SQL DW?
- python - 如何在绘图条形图轴python上仅放置真值
- laravel - Laravel 错误分页数据(渲染方法不存在)
- python - 自定义指标在每个 epoch 中经过许多步骤后变为 NaN
- javascript - 使用 AJAX 并将其链接到 html 文件 (JavaScript)
- sql - 查询以考虑具有优先级的分组的类型进行分组