Vue3新特性系列:Composition API

「这是我参与2022首次更文挑战的第38天,活动详情查看:2022首次更文挑战」。

Vue 3引入了Composition API,其灵感来自React Hooks,它将允许基于函数的方式编写组件,可以将逻辑封装到组合函数中。一个功能所定义的所有api会放在一起(更加的高内聚,低耦合)。

这样即使项目复杂,功能多,也可以快速定位到这个功能所用到的所有API,而不像vue2 Options API 中一个功能所用到的API都是分散的。

Vue核心团队将组件Composition API描述为“一套附加的、基于函数的api,允许灵活地组合组件逻辑”。

首先我们看下如何在vue2中是如何构建组件的。

Vue 2构建组件

在 Vue 2 中,我们使用 Options API来构建组件,下面是一个计数器组件。

<template>
  <div>
    <h2>Counter Options API</h2>
    <p>Count: {{ count }}</p>
    <p>2^Count: {{ countPow }}</p>
    <button @click="increment()">Increase Count</button>
    <button @click="incrementBy(5)">Increase Count by 5</button>
    <button @click="decrement()">Decrease Count</button>
  </div>
</template>

<script>
export default {
  props: {
    initialValue: {
      type: Number,
      default: 0,
    },
  },
  emits: ['counter-update'],
  data: function () {
    return {
      count: this.initialValue,
    };
  },
  watch: {
    count: function (newCount) {
      this.$emit('counter-update', newCount);
    },
  },
  computed: {
    countPow: function () {
      return this.count * this.count;
    },
  },
  methods: {
    //增加
    increment() {
      this.count++;
    },
    //减少
    decrement() {
      this.count--;
    },
    //叠加
    incrementBy(count) {
      this.count += count;
    },
  },
  mounted: function () {
    console.log('Options API counter mounted');
  },
};
</script>
复制代码

这个简单的计数器组件包括多个基本的 Vue 功能:

  • 使用一个count数据属性,该属性将该initialValue属性用作其初始值。
  • countPow作为计算属性,它计算count值的 2 次方。
  • 如果计数值已更改,则发出计数器更新事件的观察者。
  • 修改count值的多种方法。
  • 如果触发了安装的生命周期钩子,就会写下一条console.log信息。

Vue 3 Composition API 构建组件

从 Vue 3 开始,我们可以额外使用 Composition API 来构建 Vue 组件。当然,Composition API 是完全可选的,仍然可以在 Vue 3 中使用 Options API。

Composition API 是一组 API,允许我们使用导入的函数而不是声明选项来编写 Vue 组件。它是一个涵盖以下 API 的总称:

  • Reactivity API,例如ref()and reactive(),它允许我们直接创建反应状态、计算状态和观察者。
  • Lifecycle Hooks,例如onMounted()onUnmounted(),它允许我们以编程方式挂钩到组件生命周期。
  • Dependency Injection,即provide()and inject(),它允许我们在使用 Reactivity API 的同时利用 Vue 的依赖注入系统。
<script lang="ts">
import { ref, onMounted, computed, watch } from 'vue';

export default {
  props: {
    initialValue: {
      type: Number,
      default: 0,
    },
  },
  emits: ['counter-update'],
  setup(props, context) {
    const count = ref(props.initialValue);

    const increment = () => {
      count.value += 1;
    };
    const decrement = () => {
      count.value -= 1;
    };
    const incrementBy = (value: number) => {
      count.value += value;
    };

    const countPow = computed(() => count.value * count.value);

    watch(count, (value) => {
      context.emit('counter-update', value);
    });

    onMounted(() => console.log('Composition API counter mounted'));

    return {
      count,
      increment,
      decrement,
      incrementBy,
      countPow,
    };
  },
};
</script>
复制代码

上面的代码所有 Composition API 组件的入口点都是新的设置方法。它在组件创建之前和 props 解决后执行。该函数返回一个对象,并且它的所有属性都暴露给组件的其余部分。

我们可以使用该reactive方法从 JavaScript 对象创建反应状态。或者,我们可以使用ref使独立的原始值(例如,字符串、数字或布尔值)具有响应性:

import { reactive, ref } from 'vue';

const state = reactive({
  count: 0
})
console.log(state.count); // 0

const count = ref(0);
console.log(count.value); // 0
复制代码

ref对象只包含一个名为value的属性,它可以访问属性值。

Vue 3 还提供了不同的新方法,例如computedwatch, 或者onMounted我们可以在我们的setup方法中使用它们来实现我们在 Options API 组件中使用的相同逻辑。

提取合成函数

可以通过将计数器逻辑提取到一个独立的组合函数useCounter来进一步改进我们的 Vue 组件代码:

import { ref, computed, onMounted } from 'vue';

export default function useCounter(initialValue: number) {
  const count = ref(initialValue);

  const increment = () => {
    count.value += 1;
  };
  const decrement = () => {
    count.value -= 1;
  };
  const incrementBy = (value: number) => {
    count.value += value;
  };

  const countPow = computed(() => count.value * count.value);

  onMounted(() => console.log('useCounter mounted'));

  return {
    count,
    countPow,
    increment,
    decrement,
    incrementBy,
  };
}
复制代码

在 Vue 2 中,Mixins主要用于在组件之间共享代码。但是他们有几个问题:

  • 不能将参数传递给 mixin' 来改变它的逻辑,这大大降低了它的灵活性。
  • 当每个 mixin 中的属性合并到同一个组件中时,可能会发生属性名称冲突。
  • 如果一个组件使用多个 mixin,那么哪些属性来自哪个 mixin 并不一定很明显。

组合 API 解决了所有这些问题。

Composition API 的优点:

  • 通过组合 API 带来的关注点分离功能,代码更具可读性和可维护性。
  • 没有更多this关键字,因此我们可以使用箭头函数并使用函数式编程。
  • 我们只能访问我们从setup方法返回的东西,使东西更具可读性。
  • Vue 3 是用 TypeScript 编写的,完全支持 Composition API。
  • 组合函数可以很容易地进行单元测试。

下图是官方文档演示的大型组件,不同的颜色对逻辑重点进行分组,并且比较了Options API 和 Composition API:

image.png

Vue Composition API与React Hooks区别

Vue Composition API 提供与 React Hooks 相同级别的逻辑组合能力,但有一些重要区别。

首先,在react中,每次组件更新时都会重复调用React hooks。这样产生了非常多warning,还会导致性能优化问题,严重影响开发体验。

相比之下,Vue Composition API 金调用setup()script setup编码一次,这样让代码更符合使用习惯,无需担心过时的闭包,Vue Composition API调用时对调用顺序也不敏感,还可以附带条件。

Guess you like

Origin juejin.im/post/7068172634214629406