Vue 3.0 最新进展,Composition API

在上一篇文章Vue 3.0 前瞻,体验 Vue Function API,笔者经过尝试vue-function-api,提早体验了Vue 3.0 即将发布的函数式API,在文章最后,笔者提出了一些思考。最近,Vue 官方发布了最新的3.0 API 修改草案,并在充分采纳社区的意见后,将Vue Function API 更正为 Vue Composition API,提供了在Vue 2.x 可以提早体验此API的库@vue/composition-api,笔者出于学习目的,提早体验了这个库。并结合上一篇文章,描述 Vue 官方团队在采纳社区意见后对 API 做出的一些更正。javascript

本文主要分如下几个主题讨论最新的Composition API:vue

  • reactive API
  • ref API
  • watch API变化
  • computed API变化
  • 生命周期钩子变化
  • TypeScript和JSX支持

Composition API 可谓是修复了 Function API 诸多问题而提供的最新“修正案”,下面来看比起以前的vue-function-api,究竟修改了些什么呢?java

state改名为reactive

vue-function-api中,经过state建立响应式对象,这个state建立的响应式对象并非包装对象,不须要使用.value来取值。但问题在于:state一般会被用做描述 Vue 组件状态对象的变量名,容易对开发者形成误导,Vue官方团队认为将state API 改名为reactive更为优雅,reactive等价于 Vue 2.x 的Vue.observable(),用于获取一个对象的响应性代理对象:react

const obj = reactive({ count: 0 });
复制代码

value改名为ref,并提供isRef和toRefs

vue-function-api中,经过value函数建立一个包装对象,它包含一个响应式属性value。在 Vue 官方团队充分采用社区意见后,将这个API更改成refref用建立一个包装对象,只具有一个响应式属性value,若是将对象指定为ref的值,该对象将被reactive方法深度遍历。要知道, Composition API 之因此被提出和使用,就是为了让咱们更加方便地进行组件复用,将状态通过函数式地传递过程当中,因为JavaScript函数传参是值传递的,而基本类型不具有引用,为了保证属性的响应式,将使用ref来建立包装对象进行传递。git

const count = ref(0);
console.log(count.value); // 0

count.value++;
console.log(count.value); // 1
复制代码

提供isRef,用于检查一个对象是不是ref对象:github

const unwrapped = isRef(foo) ? foo.value : foo;
复制代码

若是读者你看到这里,可能就会比较疑惑了,究竟何时该使用ref,何时该使用reactive呢?其使用场景其实与咱们所习惯的编码风格密切相关,经过下面的例子,咱们能更好理解使用refreactive的区别:typescript

// 风格一:经过基本类型变量来声明状态
let x = 0;
let y = 0;

function updatePosition(e) {
 x = e.pageX;
 y = e.pageY;
}

// --- compared to ---

// 风格二:经过单一对象来声明状态
const pos = {
 x: 0,
 y: 0,
};

function updatePosition(e) {
 pos.x = e.pageX;
 pos.y = e.pageY;
}
复制代码

若是开发者习惯风格一的写法,一般经过ref将基本类型的变量转化为响应式包装对象来使其具有响应式,而若是是风格二的话,只须要建立reactive对象。api

然而,思考下面的场景:app

function useMousePosition() {
 const pos = reactive({
 x: 0,
 y: 0,
 });

 // ...
 return pos;
}

// consuming component
export default {
 setup() {
 // 对象解构将会致使响应式会被丢失
 const { x, y } = useMousePosition();
 return {
 x,
 y,
 };

 // 拓展运算符将致使响应式丢失
 return {
 ...useMousePosition()
 }

 // 只有这样才能保证响应式不被丢失
 // 经过pos.x的pos.y来取值才会保留x,y的响应式
 return {
 pos: useMousePosition()
 }
 }
};
复制代码

经过上述的例子,要知道,咱们没有办法经过编码风格的限制来保证经过组合函数返回的响应式状态不被丢失,Vue官方团队建议在组合函数中都经过返回ref对象来规避这一类问题,toRef即是作这一件事情的最好方式:函数

function useMousePosition() {
 const pos = reactive({
 x: 0,
 y: 0
 });

 // ...
 return toRefs(pos);
}

// x 和 y 如今具有了响应式
const { x, y } = useMousePosition();
复制代码

toRefsreactive对象转换为普通对象,其中结果对象上的每一个属性都是指向原始对象中相应属性的ref引用对象,这在组合函数返回响应式状态时很是有用,这样保证了开发者使用对象解构或拓展运算符不会丢失原有响应式对象的响应。

watch可做用于单一函数

比起上一篇文章中介绍的watch API 的传参方式,最新的@vue/composition-api修正案中,watch的传递方式能够收敛为单一函数,Vue 3.x 将会在其依赖的响应式状态改变是执行watch的回调函数:

const count = ref(0);

watch(() => console.log(count.value)); // 打印0

setTimeout(() => {
 count.value++; // 打印1
}, 100);
复制代码

computed可传入getset,用于定义可更改的计算属性

基本示例以下所示,与 Vue 2.x 相似的,能够定义可更改的计算属性。

const count = ref(1);
const plusOne = computed({
 get: () => count.value + 1,
 set: val => { count.value = val - 1 }
});

plusOne.value = 1;
console.log(count.value); // 0
复制代码

生命周期钩子

比起vue-function-api@vue/composition-api删除了onBeforeCreateonCreated。由于setup老是在建立组件实例时调用,即onBeforeCreate以后和onCreated以前调用,所以onBeforeCreateonCreated将可使用setup进行代替。

使用TypeScript和JSX

setup如今支持返回一个渲染函数,这个函数返回一个JSX,JSX能够直接使用声明在setup做用域的响应式状态:

export default {
 setup() {
 const count = ref(0);
 return () => (<div>{count.value}</div>);
 },
};
复制代码

注:若是使用TypeScript,同时但愿使用须要在JSX命名空间内声明如下interface

// file: shim-tsx.d.ts
import Vue, { VNode } from 'vue';
import { ComponentRenderProxy } from '@vue/composition-api';

declare global {
 namespace JSX {
 // tslint:disable no-empty-interface
 interface Element extends VNode { }
 // tslint:disable no-empty-interface
 interface ElementClass extends ComponentRenderProxy { }
 interface ElementAttributesProperty {
 $props: any; // specify the property name to use
 }
 interface IntrinsicElements {
 [elem: string]: any;
 }
 }
}
复制代码

此外,为了更好地配合 TypeScript 进行类型推断,Vue Composition API 推荐使用createComponent来定义一个组件,以便于Vue进行类型推导:

import { createComponent } from 'vue';

export default createComponent({
 props: {
 foo: String,
 },
 setup(props) {
 console.log(props.foo);
 },
});
复制代码

小结

本文是笔者上一篇文章Vue 3.0 前瞻,体验 Vue Function API的续篇,主要描述 Vue Composition API 对比 以前的草案 Vue Function API 的变化,能够看到Vue 官方针对社区建议修改了 Vue Function API 草案的诸多问题。下一篇文章中,笔者带来 Vue Composition API 的响应式对象原理解读,在解读学习过程当中,加深对 Vue Composition API 的理解。

相关文章
相关标签/搜索