-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(vue-node-registry): 修复Teleport+KeepAlive场景下DOM重复渲染的问题(#1768) #1895
Conversation
|
大佬,你这些 PR 的内容能不能整理成文章,我在 LogicFlow 掘金号上发一下,哈哈哈,或者你用你的号发,我用 LogicFlow 官方号转发一波,我感觉都挺有用的 |
可以的 完全没问题 LogicFlow 掘金号发就行🤔️甚至有空的话 这一块文章可以做大点,比如
上面的流程简单点说就是
|
安排 |
fix #1768
fix #1862
问题发生的原因
使用KeepAlive
当我们在page1的时候,先触发了
<TeleportContainer />
的渲染,然后执行new LogicFlow()
当执行
new LogicFlow()
然后进行LogicFlow.render()
后,我们会触发teleport.ts的connect方法,将当前的flowId:nodeId
作为id添加到items中此时,由于
items
是响应式的 => 它会触发收集它依赖的effect
执行,也就是getTeleport()
的setup(){return ()=> {}}
执行进行
items
的遍历,然后触发渲染出Page1
当我们从
page1
->page2
的时候,跟上面的流程类似,我们会进行new LogicFlow()
,又会重新触发一次teleport.ts
的connect
方法,将当前的flowId:nodeId
作为id添加到items中,此时items
有两个flowId
的数据!然后跟上面流程一样,由于
items
是响应式的 => 它会触发收集它依赖的effect
执行,也就是getTeleport()
的setup(){return ()=> {}}
执行而由于
KeepAlive
的特性,Page1
并没有实际销毁,它只是被隐藏了!因此此时是存在两个effect
的!!getTeleport()
的setup(){return ()=> {}}
getTeleport()
的setup(){return ()=> {}}
由于此时Page1和Page2都共用一个items(具有两个id),因此
getTeleport()
的setup(){return ()=> {}}
=> 生成Page1和Page2getTeleport()
的setup(){return ()=> {}}
=> 生成Page1和Page2这就导致了当我们从
page1
->page2
的时候,界面出现了两个Page2
,其中1个Page2
是Page1
的<TeleportContainer />
触发setup
渲染items
生成的那是因为
connect
的时候传递的container都是已确定好的,也就是items[Page2相关的id]
就只会生成Page2不使用KeepAlive
通过上面的分析,其实我们就能明白为什么不使用KeepAlive不会出现重复的Page2的现象了,那是因为Page1会自动销毁,因此不会因为
items
的变化而触发重新渲染但是不使用KeepAlive还是存在问题,问题就是当我们频繁
page1->page2->page1->page2->page1->>page2->page1
切换的时候,我们发现,items
里面的数据越来越多,就算我们主动触发LogicFlow.clearData()
也无法改变,因此这里的items
的id
销毁事件是缺失的解决方法
KeepAlive模式
为了更好解决这个问题,需要理清一下目前整体代码逻辑,以及为什么要使用
<TeleportContainer />
的写法那得从
teleport
这个组件的作用说起,本质就是在某一个组件里面写对应的逻辑代码,比如传参之类的根据这个组件的业务去决定,但是它实际渲染会根据to: container
内容去挂载DOM
如下面所示,当我们使用
<TeleportContainer>
时,我们可以在渲染的时候再传入特定的props
,比如test=1
,那么这个时候我们就可以在渲染h(Teleport)
传入特定的参数,而这个参数会跟new LogicFlow
的参数共同作用于我们构建出来的.vue 组件
换句话,就是你可以在很远的组件中进行
new LogicFlow(传入一些参数)
,这些参数在构建你声明的vue组件
时会传入,然后你可以在距离new LogicFlow(传入一些参数)
的地方进行<TeleportContainer>
触发teleport
渲染,同时传入一些你所在组件的props
特定值的参数,这样效果等同于vue3
的teleport
!所以目前的模式是没什么问题,那么问题出在哪里呢?
我们的本意是想
但是现实是
因此我们的解决方法就是
我们强制传入对应的
flowId
,进行items
的筛选不使用KeepAlive
文档以及examples更新
文档
增加了
flowId
的示例传入examples
flowId
的传入的示例