React Native栈导航场景下Redux状态变更触发双页面useEffect问题
问题根本原因
栈导航默认不会卸载已打开的页面,你调用navigation.navigate('LoginScreen')后,StartScreen仍然保留在导航栈内存中,你两个页面都订阅了Redux的loginStatus状态,所以状态变更时两个页面的监听逻辑都会触发。
可行解决方案
方案1:仅在页面聚焦时执行逻辑(最通用,支持返回前页场景)
用React Navigation提供的useIsFocused钩子判断页面是否处于前台展示状态,仅聚焦时执行状态变更的处理逻辑:
代码修改示例(两个页面都按这个改)
首先导入钩子:
import { useIsFocused } from '@react-navigation/native';
然后在组件内新增判断:
export default function StartScreen({route, navigation}) { const {loginStatus,user} = useSelector(state => state.auth); const isFocused = useIsFocused(); // 新增聚焦判断钩子 const initialRender = useRef(true); useEffect(() => { // 非聚焦页面直接跳过逻辑 if (!initialRender.current && isFocused) { if (loginStatus === 'success') { hideDialog(); navigation.reset({ index: 0, routes: [{name: 'Dashboard'}], }); } else if(loginStatus === 'failed') { alert('invalid QR code!') hideDialog(); dispatch(clearLoginStatus()) } } else { initialRender.current = false; } }, [loginStatus, isFocused]); // 依赖项新增isFocused // 剩余业务代码不变 }
方案2:跳转时替换前页(无需返回StartScreen的场景适用)
跳转LoginScreen时不用navigate,改用replace方法,直接把StartScreen从导航栈中移除并卸载:
// 把StartScreen里的登录按钮跳转逻辑修改 navigation.replace('LoginScreen')
StartScreen卸载后对应的状态监听会自动清理,不会再触发逻辑。
方案3:Redux状态区分业务场景
给auth状态新增loginType字段,标识当前是扫码登录还是账号密码登录,修改状态时传入对应的类型,两个页面仅处理对应类型的状态变更:
// Redux里修改登录状态的action新增type参数 dispatch(login({status: 'failed', loginType: 'password'})) // StartScreen里仅处理扫码登录场景 useEffect(() => { if (!initialRender.current && loginStatus === 'failed' && loginType === 'qr') { alert('invalid QR code!') // 其余业务逻辑 } }, [loginStatus, loginType]) // LoginScreen里仅处理账号密码登录场景 useEffect(() => { if (!initialRender.current && loginStatus === 'failed' && loginType === 'password') { alert('invalid credentials!') // 其余业务逻辑 } }, [loginStatus, loginType])
内容的提问来源于stack exchange,提问作者Shanu
相关产品推荐
相关产品推荐

