Vue3.2新增指令「v-memo」的正确使用姿势

926 阅读1分钟

Vue 3.2版本新增了v-memo指令,memo从字面意思理解是备忘录。它可以接受一个数组,数组中存放依赖的值,数组中的依赖值都没有发生变化时,使用v-memo的组件/元素将跳过组件更新(包括其子树)。

比如:

<template>
  <div v-memo="[name]">
    <div>{{ name }}</div>
    <div>{{ age }}</div>
    <div>{{ message }}</div>
  </div>
  <button @click="handleBtnClick">change</button>
</template>
<script setup>
import { ref } from 'vue';

const name = ref('loftyamb')
const age = ref(24)

const handleBtnClick = () => {
  age.value++ // age值的变化将不会更新到页面中,除非name发生变化
}

v-memo能够在一些场景下对性能进行细小的优化(不该被滥用),例如:

假设我们有一个长列表需要渲染,并且列表项会因为用户的操作发生变化:

<template>
  <div class="memo-demo">
    <ul>
      <li 
        v-for=" item  in 5" 
        :key="item" 
        :class="{ active: item === active }" 
        @click="handleItemClick(item)"
        :ref="handleRefChange">
        {{ item }}
      </li>
    </ul>
  </div>
</template>
<script setup>
  import { ref } from 'vue'

  const handleRefChange = () => {
    console.log('change');
  }
  const active = ref(1);
  const handleItemClick = (item) => {
    active.value = item;
  };
</script>
<style scoped>
  .active {
    color: red;
  }
</style>

上面代码中的handleRefChange会在每次绑定ref的元素更新时(包括初始化)被调用,我们可以在浏览器控制台中看到li元素初始化的时候被调用5次(因为遍历生成了5个li元素):

而如果我们点击其中一个非active的li元素时,我们会发现handleRefChange又再次被调用了5次,也就是5个li元素都发生了更新(因为它们所依赖的active值变化了):

但实际上,我们并不需要对每个li元素都进行更新,只需要对所依赖item === active的值发生更新的时候才进行更新即可。在这种情况下,我们可以使用v-memo指令来实现优化:

<li 
  v-for=" item  in 5" 
  :key="item" 
  :class="{ active: item === active }" 
  @click="handleItemClick(item)"
  v-memo="[item === active]"
  :ref="handleRefChange">
    {{ item }}
  </li>

当使用了v-meomo指令之后,我们就会发现每次点击非active的li元素的之后,handleRefChange只被调用2次,因为只有点击之前「active的li元素」和「被点击的li元素」所依赖的item === active值会发现变化:

通过v-memo指令,我们可以在更新内容很多时减少一些不必要的更新,从而对性能进行优化。