
前言
Vue 3 为我们提供了一些开箱即用的显着性能改进,但也引入了一些额外的手动功能,可以帮助提高我们的应用程序性能。
在本文中,我们将讨论一个名为v-memo. 该指令已在 Vue 3.2 中引入,据我所知,它不会在 Vue 2 中可用。该指令的目的是帮助您提高中/大型 Vue 应用程序的性能,它不是旨在用于小型应用程序。
什么是v-memo
v-memo用于记忆与一组固定的依赖值相关的组件的子树。子树将延迟所有未来的更新,直到其中一个依赖项值发生更改。
即使上面这句话看起来很吓人,但实际上,事情很容易理解。所做的与我们的计算属性已经发生的相同,但只是应用于 DOM 的一部分。v-memo
这个新指令将缓存它控制的 DOM 部分,并在特定值发生变化时运行更新并重新渲染它。这些值由开发人员手动设置。
一个基本的例子v-memo
示例始终是理解新技术的最佳方式,因此让我们直接进入并提供一个小示例来开始并了解该指令的语法和用法:
<template>
<div>
..the rest of the component
<div v-memo="[myValue]">
<svg >
<title>{{MyValue}}</title>
...
</svg>
<vue-custom-element :value="myValue"></vue-custom-element>
</div>
</div>
</template>
让我们详细看看上面实现了什么:
.. the rest of the component
需要解释的第一行是 v-memo 通常被用作组件的一部分,它应该只影响组件 dom 的子集。所以在这个例子中,我们希望组件实际上比我刚刚粘贴的要大。
<div v-memo="[myValue]">
接下来,我们将我们分配给特定的 DIV 及其所有子元素。当调用 v-memo 时,我们必须传递一个值数组来控制子树的渲染。v-memo
该数组接受多个值之一”以及类似的表达式。v-memo="[valueOne, valueTwo]v-memo="myValue === true"
注意:使用空数组调用将等同于使用,并且只会渲染组件的该部分。v-memo
v-once
<svg >
<title>{{MyValue}}</title>
...
</svg>
<vue-custom-element :value="myValue"></vue-custom-element>
现在是时候关注我们的子树的内容了。在我的示例中,我使用了原生元素“SVG”和自定义 Vue 元素“vue-custom-element”。我这样做是为了强调其中包含的 HTML可以是任何东西。v-memo
当我们的内部 HTML 是原生元素(div、SVG、按钮、表单)时,在非常大的数据集(如大表)或非常复杂的嵌套 DOM(如动态 SVG)上使用时,使用只会很有用。v-memo
虽然,在自定义组件上使用不仅会停止 HTML 的呈现,而且实际上也会停止 Vue 组件的响应式更新(监视、计算等)。当与 Vue 自定义元素一起使用时,v-memo 在子组件的渲染成本非常高且我们能够“推迟”其更新到特定场景的情况下非常有用。v-memo
几个例子
本节将包含几个快速示例,以提供更多上下文并帮助理解此功能何时真正有用。
我想强调的是,这个特性是为高级用户准备的,应该只用于那些小的性能改进非常重要的复杂应用程序。
错误的案例
当使用实际上不正确并且不会提供任何性能优势时,我将首先编写。v-memo
<div v-memo="[myValue]">
<p>Static content, no vue values here</p>
</div>
在上面的示例中,不需要记住包含在其中的子树,因为它实际上是静态的并且不会更改(它不包含任何 Vue 变量)。Vue 3 虚拟 DOM 管理能够自动了解 DOM 的哪一部分是静态的,哪一部分不是。v-memo
无论 HTML 多么复杂,在静态 HTML 上添加都不会有用。v-memo
管理更新
在某些情况下,不仅可以用来提高性能,还可以通过控制组件的更新周期来实际改善 UX(用户体验)。v-memo
<div v-memo="[allFieldChanged]">
<p>{{ field1 }}</p>
<p>{{ field2 }}</p>
<p>{{ field3 }}</p>
<p>{{ field4 }}</p>
</div>
在上面的示例中,更改单个字段,例如 field1 不会导致重新渲染。事实上,新字段只会在所有字段都更新后才会显示。
我最近遇到了一种情况,即子组件会更新并对大型 JSON 数据集做出反应。在这种情况下,使用真的有助于在所有更改完成后触发更新。v-memo
与 v-for 结合使用
using 最常见的用例之一是处理使用.v-memov-for
<div v-for="item in list" :key="item.id" v-memo="[item.id === selected]">
<p>ID: {{ item.id }} - selected: {{ item.id === selected }}</p>
<p>...more child nodes</p>
</div>
在上面直接取自 Vue 文档的示例中,我们在实践中看到了/语法。v-forv-memo
如果没有在上面的代码中使用,“selected”变量的每次更改都会导致列表的完整重新呈现。新指令提供的记忆功能允许框架仅更新表达式发生更改的行,因此在选择或取消选择项目时。v-memoitem.id === selected
如果我们考虑一个包含 1000 个条目的列表。与上面的代码一起使用,将节省每次更改的 998 个条目的评估和重新渲染!不错!v-memo
无意中停止子组件触发更新
最后一个例子是我最近遇到的一个极端案例。在本文的大部分内容中,我们都强调了将阻止子树呈现更新的事实,但重要的是要意识到,使用该指令实际上会停止执行可能由更新触发的任何代码。v-memo
让我们看下面的例子:
<div v-memo="[points > 1000]">
<myComponent :points="points" />
</div>
//myComponent
<isLevel1 v-if="points <= 1000">....</isLevel1>
<isLevel2 v-if="points > 1000">...</isLevel2>
<script>
...,
watch: {
points() {
logPointChange();
}
}
如果我们假设内部组件“isLevel1”和“isLevel2”很复杂,避免使用它们的渲染似乎是个好主意。不幸的是,避免重新渲染也将避免在. 在我们的示例中,这意味着在属性“points”上注册的手表不会运行,除非变量“points”在级别阈值之间发生变化。v-memomyComponent
这个问题很容易解决,因为我们需要做的就是将 log 方法移动到我们的父级,但重要的是要记住执行完全被.v-memo
总结概括
这个新指令非常强大,权力越大,责任越大。在性能是关键并且我们正在开发大型应用程序的情况下,使用它确实应该是最后的选择。