v-if,v-show控制的是是否渲染,而真正的性能瓶颈,往往在于是否需要重新渲染
面对这个问题,v-if和v-show显的有些无力,而Vue3有一个专门解决此问题的指令:v-memo
# 什么是v-memo
v-memo是一个指令,作用是有条件的跳过一个元素或组件的更新,语法如下:
<div v-memo="[depA, depB]">
...
</div>
v-memo接收一个依赖数组,只有当数组至少一个值与上次渲染相比发生了变化,Vue才会重新渲染这个div及其子节点。否则将跳过diff过程
# v-memo 的使用场景
v-memo不是用来替代v-if或v-show的,它是专门解决那些令人棘手的渲染性能问题。
其最经典、最有效的应用场景就是优化超长v-for列表,假设有一个包含100个用户的列表,每个用户都有name和status(在线/离线)两个属性
没有 v-memo版本
<template> <div v-for="user in users" :key="user.id"> <span>{{ user.name }}</span> <span>{{ user.status }}</span> </div> </template>当用户状态发生变化时,整个列表都会重新渲染,即使只有1个用户的状态发生了变化;Vue理论上需要遍历整个列表,为每个节点创建新的VNode并diff
有 v-memo版本
<template> <div v-for="user in users" :key="user.id" v-memo="[user.status]"> <span>{{ user.name }}</span> <span>{{ user.status }}</span> </div> </template>需要注意的是
v-memo="[user.status]"当某个用户的status改变时,只有他对应的div的v-memo依赖项发生变化,于是只有这个div会被重新渲染,Vue会直接跳过其他999个用户的整个更新过程。
通过一行代码,我们将O(n)的更新检查开销,降低到O(1)
# 对比
v-once本质上就是v-memo的一个特例,v-once等同于 v-meo="[]"。因为依赖数组是空的,它永远不会改变,所以组件只会在首次渲染后被永远冻结。
v-if 和 v-show 的争论,解决的是“有或无”的渲染问题,但现代前端应用中,更大的性能挑战来自于“多与少”的更新问题。