Vue3-组合式API

2,303 阅读8分钟

Vue3-组合式API

大多数前端VUE开发者会有个疑问为什么要用Composition API。什么时候要用,怎么去用,能给我们带来什么好处。本教程就解决以上以为,解决这个疑问我们先从了解VUE2的缺点开始,也可以说VUE2的下列局限性导致了组合式API的产生:

  • 基于Vue2的大型组件很难维护。
  • 基于Vue2封装的组件逻辑复用困难。
  • Vue2对TypeScript支持有限。

下面我们重点讨论前两个问题,只要把这前连个问题讨论清楚了,也就明白了组合式API解决了什么问题。

基于Vue2选项式API封装的大型组件很难维护

为了说明这个问题我们拿一个搜索组件为例,它主要完成在网站上搜索产品功能。为更形象说明问题我们采用需求功能渐进增加的方式来描述。

该组件采用标准的Vue2语法进行封装,如下图所示

当产品经理要求我们再增加一个对查询结果排序的功能时,我们的逻辑可能会变成如下这样:

从以上简单的2个功能看,代码还不算糟糕,但是当我们在这个组件不断增加功能需求时,比如增加搜索过滤,结果分页。我们的同一逻辑代码将在不同选项(components, props, data, computed, methods, and lifecycle methods)中进行拆封,从而导致我们逻辑关注点分散,不能很好的对组件理解,降低了阅读可读性。如果我们用颜色标注同一逻辑(如下标红处),能很形象的看出代码是多么的分散,很难理解哪些代码与哪些功能逻辑有关。

正如我们想象的那样(如上图标绿处),如果我们能够将同一逻辑代码保持在一起,那么我们的代码将更具可读性,从而更易于维护。那么这个例子如果采用composition API把代码组合在一起,它会是这样:

如上图所示我们需要使Vue3 的 composition API。setup()中的代码是我将在后面的教程中要讲到的新方法。值得注意的是,这种新方法完全是可选的,编写Vue组件的选项式接口方法仍然是完全有效的。

当有有些开发人员初次看到此setup时,可能会想“我们是不是会把所有逻辑代码都写在setup方法中,如此以来代码逻辑会不会变得更难理解和阅读了”。这个疑问就如同vue3刚刚开源时一大堆的吐槽一样。吐槽的根源在于大多说并没有对setup的本质有所了解。当我们真正按官方要求的那样把重用逻辑封装到组合函数中去,再在setup中引用时就不会出现上述问题,如下的组织代码。

现在,我们已经了解了组件API如何使大型组件更具可读性和可维护性,接下来我们将讨论Vue 2的第二个限制。

基于Vue2选项式API封装的组件逻辑复用困难。

当涉及到跨组件重用代码时,在Vue 2中有3种很好的解决方案来实现这一点,但是每种方案都有其局限性。让我们用我们的示例来逐一讲解。首先看一下混合(Mixins),如下图所示

采用混合方式的优点如下:

  • mixin可以根据逻辑关注点进行组织代码

采用混合方式的缺点也很明显:

  • 它们容易发生冲突,最终可能导致属性名称冲突。
  • 不清楚混合元素如何作用
  • 混合后的组件属性不方便在其他组件中重用。

针对最后一项使我们看一下Mixin工厂,这些函数返回自定义Mixin。

从上图可以看出混合工厂允许我们通过配置命名空间来自定义混合,从而可以在多个组件中使用。通过此方式有如下优点:

  • 现在我们通过定义命名空间轻松实现重用。
  • 复用方法之间的关系更加明确。

但同时也具有如下缺点:

  • 命名空间需要严格规范,才能确保不冲突。
  • 仍然不能避免隐式属性,这意味着我们必须查看Mixin内部以找出它公开的属性。
  • 在运行时没有相应实例可访问,因此无法动态生成Mixin工厂。

比较庆幸的是,还有一种解决方案,也就是我们常用的-作用域插槽:

采用插槽方案有如下优点:

  • 解决了Mixins的几乎所有缺点。

但同样也有缺点:

  • 您的配置最终出现在模板中,理想情况下,模板应仅包含我们要呈现的内容。
  • 它们会增加模板的缩进量,从而降低可读性。
  • 公开的属性仅在模板中可用。
  • 由于我们使用的是3个组件而不是1个,因此性能有所降低。

正如我们看到的,每种解决方案都有局限性。Vue 3的composition API为我们提供了组织复用代码的第四种方案,如下图所示:

现在,我们将使用composition API内部的函数来创建组件,这些函数会在我们的setup()方法中导入并使用。

组合式API的优点:

  • 由于是基于函数的相对以上方案编写的代码更少,因此将功能部件从组件中提取到函数中更加容易。
  • 由于您已经熟悉函数编写,因此它以您现有的技能为基础,入手更容易。
  • 它比Mixins和Scoped插槽更灵活,因为它们只是个函数。
  • 对代码编辑器更友好,结合强类型能实现智能提示,编写代码体验大大增加。

事情没有完美的,同样也存在缺点:

  • 需要学习新的低级API来定义composition API。
  • 现在有两种编写组件的方法,而不仅仅是标准语法。

以上为大家讲解了为什么要用composition API,接下来我们引用官方文章做一下总结:

1、更好的逻辑复用与代码组织

我们都因 Vue 简单易学而爱不释手,它让构建中小型应用程序变得轻而易举。但是随着 Vue 的影响力日益扩大,许多用户也开始使用 Vue 构建更大型的项目。这些项目通常是由多个开发人员组成团队,在很长一段时间内不断迭代和维护的。多年来,我们目睹了其中一些项目遇到了 Vue 当前 API 所带来的编程模型的限制。这些问题可归纳为两类:

  1. 随着功能的增长,复杂组件的代码变得越来越难以阅读和理解。这种情况在开发人员阅读他人编写的代码时尤为常见。根本原因是 Vue 现有的 API 迫使我们通过选项组织代码,但是有的时候通过逻辑关系组织代码更有意义。
  2. 目前缺少一种简洁且低成本的机制来提取和重用多个组件之间的逻辑。

Composition API 为组件代码的组织提供了更大的灵活性。现在我们不需要总是通过选项来组织代码,而是可以将代码组织为处理特定功能的函数。这些 API 还使得在组件之间甚至组件之外逻辑的提取和重用变得更加简单。

2、更好更好的类型推导

另一个来自大型项目开发者的常见需求是更好的 TypeScript 支持。Vue 当前的 API 在集成 TypeScript 时遇到了不小的麻烦,其主要原因是 Vue 依靠一个简单的 this 上下文来暴露 property,我们现在使用 this 的方式是比较微妙的。(比如 methods 选项下的函数的 this 是指向组件实例的,而不是这个 methods 对象)。换句话说,Vue 现有的 API 在设计之初没有照顾到类型推导,这使适配 TypeScript 变得复杂。

当前,大部分使用 TypeScript 的 Vue 开发者都在通过 vue-class-component 这个库将组件撰写为 TypeScript class (借助 decorator)。我们在设计 3.0 时曾有一个已废弃的提案,希望提供一个内建的 Class API 来更好的解决类型问题。然而当讨论并迭代其具体设计时,我们注意到,想通过 Class API 来解决类型问题,就必须依赖 decorator——一个在实现细节上存在许多未知数的非常不稳定的 stage 2 提案。基于它是有极大风险的。

Composition API 撰写的代码会完美享用类型推导,并且也不用做太多额外的类型标注。这也同样意味着你写出的 JavaScript 代码几乎就是 TypeScript 的代码。即使是非 TypeScript 开发者也会因此得到更好的 IDE 类型支持而获益。