react 项目使用 keepalive 抽屉弹窗卡死问题
问题:react 项目当页面使用 keepalive后,在当前页面打开弹窗抽屉等组件时,点击后退页面。会出现背后页面后退,弹窗抽屉等组件未关闭,且关闭不了的现象。
react-keep-alive 原理
在 KeepAlive 组件中,通过 AliveScope 高阶组件获取到 keep 函数。在组件的初始化阶段,调用 init 方法,将组件的 id、children 和 keep 函数传递进去。在 init 方法中,调用 keep 函数,并使用 Promise 的 resolve 回调函数将真实的组件内容添加到 placeholder(占位符)div 节点中。 最后,在 KeepAlive 组件中,通过 ref 获取到 placeholder 节点,并将其保存为实例属性。这样,当 KeepAlive 组件再次渲染时,placeholder 节点已经包含了之前缓存的真实组件内容,所以实际上不再需要重新渲染组件,只需将 placeholder 节点直接添加到 DOM 树中。 简单概括:
- AliveScope组件拿到 KeepAlive组件传来的虚拟 dom 进行渲染,这样在 fiber 树上会表示这个组件已经被渲染了;
- 渲染后AliveScope组件将这个 dom 传给KeepAlive组件,KeepAlive组件获取 dom 后将其插入自己渲染的 dom 里;
- 这样就会导致,AliveScope组件渲染了 dom,并且有这个 dom 的 fiber,享受AliveScope组件的生命周期,但是渲染确实按照KeepAlive组件的渲染逻辑走,当KeepAlive组件卸载时,fiber 会 commit 掉子组件的 dom。
- 当KeepAlive组件重新显示时,会调用 AliveScope 方法,重新获取 KeepAlive 组件已经渲染的 dom。(也有说是缓存在 fiber 树上)
分析原因:react-router在对路由匹配时,不匹配的就直接卸载了。而react 的 keepalive 组件使用的原理是将 dom 缓存在AliveScope 组件中,当路由变化时页面 dom 被缓存在 fiber 树上而未被卸载,导致抽屉组件不会被卸载。
解决方案
-
将 drawer/modal 等组件挂载在当前页面上 将 drawer 挂载在父级 div 上,能解决路有变化隐藏 drawer/modal,且不会影响层级(包括微应用)。但体验会有些不好,会有闪屏情况出现。
-
删除 KeepAlive
该方案需要与产品确定,目前已咨询童格,暂时无法确定。如需修改切记与产品同步。
因为目前详情交互改为抽屉打开,关闭不会影响列表页筛选和分页,顾不需要KeepAlive功能缓存页面信息,可逐步删除 KeepAlive
目前出现的资源微服务与 pms-react-pc应用 KeepAlive组件多数在 app.tsx
里包裹,可直接删除。(注意:微应用代码有两处 KeepAlive需要删除)