Vue 3.0笔记——组合式API(介绍)
什么是组合式API?
通过创建Vue组件,我们可以将接口的可重复部分及其功能提取到可重用的代码段中。仅此一项就可以使我们的应用程序在可维护性和灵活性方面走得更远。然而,我们的经验已经证明,光靠这一点可能是不够的,尤其是当你的应用程序变得非常大的时候——想想几百个组件。在处理如此大的应用程序时,共享和重用代码变得尤为重要。
假设在我们的应用程序中,我们有一个视图来显示某个用户的仓库列表。除此之外,我们还希望应用搜索和筛选功能。处理此视图的组件可能如下所示:
该组件有以下几个职责:
从假定的外部API获取该用户名的仓库,并在用户更改时刷新它;使用searchQuery字符串搜索存储库;使用filters对象筛选仓库。用组件的选项(data、computed、methods、watch)组织逻辑在大多数情况下都有效。然而,当我们的组件变得更大时,逻辑关注点的列表也会增长。这可能会导致组件难以阅读和理解,尤其对于那些一开始就没有编写这些组件的人来说。
碎片化使得理解和维护复杂组件变得困难。选项的分离掩盖了潜在的逻辑问题。此外,在处理单个逻辑关注点时,我们必须不断地“跳转”相关代码的选项块。
如果我们能够将与同一个逻辑关注点相关的代码配置在一起会更好。而这正是组合式API使我们能够做到的。
既然我们知道了为什么,我们就可以知道怎么做。为了开始使用组合式API,我们首先需要一个可以实际使用它的地方。在Vue组件中,我们将此位置称为setup。
setup组件选项
新的setup组件选项在创建组件之前执行,一旦props被解析,并充当合成API的入口点。
setup选项应该是一个接受props和context的函数。此外,我们从setup返回的所有内哦让那个都将暴露给组件的其余部分(计算属性、方法、声明周期钩子等等)以及组件的模板。
让我们添加setup到我们的组件中:
现在让我们从提取第一个逻辑关注点开始(在原始代码段中标记为“1”)。
1.从假定的外部API获取该用户的仓库,并在用户更改时刷新它。我们将从最明显的部分开始:
仓库列表;更新仓库列表的函数;返回列表和函数,以便其他组件选项可以访问它们。这是我们的出发点,但它还不能工作,因为我们的repositories变量是非响应式的。这意味着从用户的角度来看,仓库列表将保持为空。我们来解决这个问题!
带ref的响应式变量
在Vue 3.0中,我们可以通过一个新的ref函数使任何响应式变量在任何地方起作用,如下所示:
ref接受参数并返回它包装在具有value property的对象中,然后可以使用该property访问或更改响应式变量的值:
在对象中包装值似乎不必要,但在JavaScript中保持不同数据类型的行为统一是必需的。这是因为在JavaScript中,Number或String等基本类型是通过值传递的,而不是通过引用传递的:
在任何值周围都有一个包装器对象,这样我们就可以在整个应用程序中安全地传递它,而不必担心在某个地方失去它的响应性。
回到我们的例子,让我们创建一个响应式的repositories变量:
完成!现在,每当我们调用getUserRepositories时,repositories都将发生变化,视图将更新以反映更改。我们的组件现在应该如下所示:
我们已经将第一个逻辑关注点中的几个部分移到了setup方法中,它们彼此非常接近,剩下的就是在mounted钩子中调用getUserRepositories,并设置一个监听器,以便在user prop发生变化时执行此操作。
我们将从生命周期钩子开始。
生命周期钩子注册内部setup
为了使组合式API的特性与选项API相比更加完整,我们还需要一种在setup中注册生命周期钩子的方法。这要归功于从Vue导出的几个新函数。组合式API上的生命周期钩子与选项式API的名称相同,但前缀为on:即mounted看起来像onMounted。
这些函数接受在组件调用钩子时将执行的回调。
让我们将其添加到setup函数中:
现在我们需要对user prop所做的更改做出反应。为此,我们将使用独立的watch函数。
watch响应式更改
就像我们如何使用watch选项在组件内的user property上设置侦听器一样,我们也可以使用从Vue导入的watch函数执行相同的操作。它接受3个参数:
一个响应式引用或我们想要侦听的getter函数;一个回调;可选的配置选项。下面让我们快速了解一下它是如何工作的:
例如,每当counter被修改时counter.value=5,watch将触发并执行回调(第二个参数),在本例中,它将把“The new counter value is: 5”记录到我们的控制台中。
以下是等效的选项式API:
现在我们将其应用到我们的示例中:
你可能已经注意到在我们的setup的顶部使用了toRefs。这是为了确保我们的侦听器能够对user prop所做的更改做出反应。
有了这些变化,我们就把第一个逻辑关注点移到了一个地方。我们现在可以对第二个关注点执行相同的操作——基于searchQuery进行过滤,这次是使用计算属性。
独立的computed属性
与ref和watch类似,也可以使用从Vue导入的computed函数在Vue组件外部创建计算属性。让我们回到我们的counter例子:
在这里,computed函数返回一个作为computed的第一个参数传递的getter类回调的输出的一个只读的响应式引用。为了访问新创建的计算变量的value,我们需要像使用ref一样使用.value property。
让我们将搜索功能移到setup中:
对于其他的逻辑关注点我们也可以这样做,但是你可能已经在问这个问题了——这不就是把代码移到setup选项并使它变得非常大吗?嗯,那是真的。这就是为什么继续其他任务之前,我们首先将上述代码提取到一个独立的组合式函数。让我们从创建useUserRepositories开始:
然后是搜索功能:
现在在单独的文件中有了这两个功能,我们就可以开始在组件中使用它们了。以下是如何做到这一点:
此时,你可能已经知道了这个练习,所以让我们跳到最后,迁移剩余的过滤功能。