React类组件未使用useEffect 登录跳转时为何触发卸载后状态更新警告?
问题根因
该警告和是否使用useEffect没有关联,是类组件异步流程的时序漏洞导致的,触发点有两个:
- 登录页的必执行时序漏洞:登录成功执行
this.props.navigation.navigate("App")后,原登录栈会被React Navigation从路由树中整体移除,对应的登录页组件被卸载。但async函数的finally块是强制执行的,等登录接口走完、finally执行actions.setSubmitting(false)时,这个Formik的状态更新方法已经绑定在已卸载的登录页实例上,直接触发未挂载组件更新的警告。 - 搜索页的参数错误与判断逻辑缺陷:
initial方法内调用this.props.firebase.getUser(user)时,把未定义的局部变量user当作入参传入,会导致这个异步请求的返回时序完全不可控;同时代码仅把_isMounted判断加在所有异步操作完成后的最后一步,组件在异步等待间隙被卸载时,前面的AsyncStorage写入、推送权限申请、firebase token设置操作依然会无条件走完,只要时序卡到组件卸载后执行状态更新,就会触发警告。
逐点修复方案
登录页(loginScreen.js)改造
- 为类组件新增挂载状态标记,初始值为
false,在componentDidMount生命周期设为true,在componentWillUnmount生命周期设为false - 给finally块里的状态更新操作加上挂载状态判断:
finally { // 仅在组件仍挂载时更新提交状态 if (this._isMounted) { actions.setSubmitting(false) } }
搜索页(searchScreen.js)改造
- 修正
initial方法的参数错误:给this.props.firebase.getUser传入正确的用户身份参数,不要传递未定义的局部变量user,避免异步请求异常打乱执行时序 - 把挂载状态判断前置到每一个await节点之后,一旦检测到组件已卸载,直接中断后续所有逻辑,不要继续执行存储写入、网络请求、状态更新操作
- 所有异步请求(axios、firebase接口、原生API)返回后,第一时间检查
_isMounted状态,值为false时直接return,不要执行后续的setState、导航跳转逻辑
注意:目前搜索页的
_isMounted判断逻辑是失效的——只在最后设置isLoading状态时做了检查,前面整段异步链路都没有拦截,哪怕组件已经卸载,链路依然会完整执行,这也是明明加了_isMounted标记却依然报警告的核心原因。
内容的提问来源于stack exchange,提问作者Kaepxer
相关产品推荐
相关产品推荐

