背景
keep-alive是为数不多我们可以手动对框架性能进行优化的组件,那我们是不是可以全部组件都加上keep-alive进行wrap,这样可以获取更高的性能呢?
本文主要是通过源码来解释下keep-alive的使用场景;
feature
keep-alive主要实现两个功能:
1 通过LRU算法更新组件缓存(主要是更有效的利用内存,避免内存溢出);
2 缓存组件;
关于LRU算法部分不再赘叙,我们主要看下是如何实现缓存组件的,先看下源码关于这部分的代码:
render () {
const slot = this.$slots.default
const vnode: VNode = getFirstComponentChild(slot)
const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions
if (componentOptions) {
// check pattern
const name: ?string = getComponentName(componentOptions)
const { include, exclude } = this
if (
// not included
(include && (!name || !matches(include, name))) ||
// excluded
(exclude && name && matches(exclude, name))
) {
return vnode
}
const { cache, keys } = this
const key: ?string = vnode.key == null
// same constructor may get registered as different local components
// so cid alone is not enough (#3269)
? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '')
: vnode.key
if (cache[key]) {
vnode.componentInstance = cache[key].componentInstance
// make current key freshest
remove(keys, key)
keys.push(key)
} else {
// delay setting the cache until update
this.vnodeToCache = vnode
this.keyToCache = key
}
vnode.data.keepAlive = true
}
return vnode || (slot && slot[0])
}
keep-alive是没有写template模板,通过render函数处理渲染结果。但可以看出来有如下特性:
1 当渲染keep-alive里的组件时候,会先找下是否存在缓存;
2 通过当前实例中的cache[key]来缓存实例的,意味着如果当前父组件卸载的话缓存也失效了;
根据这些特性,可以看出来我们应该在什么场景中去使用keep-alive;
使用场景
1 vue-router,因为router的父元素是不会卸载的,所以在切换不同router中我们是可以缓存不同页面组件的;
2 动态组件,e.g.
<keep-alive>
<component :is="view"></component>
</keep-alive>
因为官方有推荐在动态组件使用keep-alive,所以我主要是在动态组件的情景下想使用keep-alive,所以这里多说一下。我原本是想按照上面这个demo的方式来使用keep-alive的,但其实是毫无效果的,两个原因:
1 父组件更新时候是不会导致动态组件更新的;
2 父组件如果卸载了,动态组件的缓存也没有了;
那到底什么场景下可以在动态组件下使用keep-alive呢?e.g.
<keep-alive>
<component :is="view1" v-if="show === 'view1'"></component>
<component :is="view2" v-if="show === 'view2'"></component>
</keep-alive>
当我们在父组件中通过v-if来判断显示不同内容时可以使用(跟vue-router类似)。但其实也不一定需要用keep-alive,也可以考虑例如v-show来保持其他模块的渲染。
问题记录
1 keepalive的组件缓存之后再激活是否会触发生命周期钩子?
不会,但vue提供了另外的生命周期钩子给缓存的组件触发(onActivated在组件激活时触发, onDeactivated非激活状态触发)。
总结
其实这次了解keep-alive,除了了解到它的用法之外。还了解到vue和react hooks渲染的不同,react其实相当多一部分优化是在处理父组件rerender导致的子组件rerender,但vue的更新粒度是在组件层级的,父组件的更新并不会导致子组件的更新,所以优化的方式也有些区别。