React Native与React Navigation屏幕转场状态处理及未定义异常解决
嘿,我太懂你踩的这个坑了——React Navigation默认会保留栈内页面的实例,加上Redux状态是全局共享的,目标页清掉user后,后台的源页面还在抱着这个已经变成undefined的对象不放,一切换回来就炸。给你几个不用到处写if (user)的省心解法:
1. 给Redux Selector加兜底默认值
从根源上解决问题,在获取user的selector里直接设置默认空对象,这样组件拿到的永远不会是undefined:
// 比如你的selectors文件里 export const selectUser = (state) => state.user || {};
之后组件里用这个selector取数据,哪怕store里的user被清了,拿到的也是空对象。要是需要更贴合业务的默认值,把{}换成{ name: '匿名用户', id: null }这类结构就行,访问属性时再也不会抛未定义异常。
2. 用可选链操作符简化检查
ES2020的可选链?.简直是这类场景的救星,不用写一堆嵌套的条件判断:
// 源页面组件里 const user = useSelector(selectUser); // 之前可能要写 user && user.name,现在直接用 const userName = user?.name || 'Guest';
哪怕user是undefined或者null,user?.name只会返回undefined,不会抛出异常,再配合||设置默认值,代码清爽多了。
3. 监听状态变化自动跳转
如果源页面在user清空后就没有存在的意义了,直接在源页面里监听user的状态,一旦变成空就自动跳转到合适的页面(比如登录页):
// 函数组件用useEffect,类组件用componentDidUpdate useEffect(() => { if (!user) { navigation.navigate('Login'); } }, [user, navigation]);
这样目标页一清空user,源页面就会自动跳转,根本不会给用户切回来报错的机会。
4. 导航时重置栈销毁源页面
要是跳转后完全不需要再回到源页面(比如登录后跳主页、退出登录),别用navigate,改用reset方法清空栈并替换成目标页,让源页面直接被销毁:
// 源页面里的跳转代码 navigation.reset({ index: 0, routes: [{ name: 'TargetPage' }], });
这种方式直接从页面实例层面解决问题,彻底避免后台页面引用过期状态。
总结下来,前两种方法是最通用的,不用改业务逻辑就能搞定大部分场景;如果业务上有明确的页面生命周期要求,后两种方法更合适。
内容的提问来源于stack exchange,提问作者Warren

