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 的理解。

相關文章
相關標籤/搜索