在上一篇文章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
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 });
複製代碼
在vue-function-api中,經過value
函數建立一個包裝對象,它包含一個響應式屬性value
。在 Vue 官方團隊充分採用社區意見後,將這個API更改成ref
。ref
用建立一個包裝對象,只具有一個響應式屬性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
呢?其使用場景其實與咱們所習慣的編碼風格密切相關,經過下面的例子,咱們能更好理解使用ref
和reactive
的區別: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();
複製代碼
toRefs
將reactive
對象轉換爲普通對象,其中結果對象上的每一個屬性都是指向原始對象中相應屬性的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
可傳入get
和set
,用於定義可更改的計算屬性基本示例以下所示,與 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刪除了onBeforeCreate
和onCreated
。由於setup
老是在建立組件實例時調用,即onBeforeCreate
以後和onCreated
以前調用,所以onBeforeCreate
和onCreated
將可使用setup
進行代替。
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 的理解。