Vue Composition API 筆記(上)

Eason Lin
9 min readSep 20, 2020

--

有一陣子沒有寫部落格了,自從上工後第一份專案準備上線加上其他私事後,技術學習如 Vue SSR 解決方案 nuxt.js 、Vanilla JS 及前端相關知識等等的都是斷斷續續沒規劃地(想到才)學,昨天看到了神Q超人的這篇文,才驚覺自己已經很久沒有寫 Medium 了

Vue3 在兩天前正式釋出了,之前就一直常常看到 composition API 這個關鍵字,藉著這個時間點稍微了解了其使用方式,簡略做個筆記。

Composition API 只是 Vue3 中另一種編寫組件的方法 ,在 Vue3 中仍然可使用 Vue2 編寫組件的方法,其好處如下:

  • 提供更好的 TypeScript 支持
  • 組件太大,需要依功能分類時可使用
  • 需要跨組件使用程式碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vue v3</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="app">
<h1>{{msg}}</h1>
<button @click="addExclamationMark()">Add !</button>
</div>
<script>
const { ref } = Vue;
const App = {
setup() {
const msg = ref("Hello Vue 3");
function addExclamationMark() {
msg.value += "!";
}
return {
msg,
addExclamationMark,
};
},
};
Vue.createApp(App).mount("#app");
</script>
</body>
</html>

首先,藉由 const { ref } = Vue; 取得 Vue 的 ref 方法

setup() 會在 Components, Props, Data, Methods, Computed PropertiesLifecycle Methods 前執行,並且不能在其中存取 this

如果在 setup 階段中把 msg log 出來,看起來會是這樣:

因此在 addExclamationMark 需要在 msg.value 才能改變 msg 在模板中的值;當 Vue 在模板中發現 ref 時,它會自動暴露(expose)出其內部的值,因此在模板中僅透過 {{msg}} 便能取得 “Hello Vue 3”,最後透過 return 將值及函式回傳至模板。

使用計算屬性

若要在 Composition API 使用計算屬性,需先從 Vue 中取得 computed

const { ref, computed } = Vue;

撰寫計算屬性:

const exclamationMarkLength = computed(() => { 
return msg.value.match(/!/g)?.length || 0;
});

並 return 讓模板可以存取

return {   
// ...
exclamationMarkLength,
};

模組化地使用

我們可以像這樣將程式碼提取作為函式讓其可以重複使用

const App = {
setup() {
return helloVueFunc();
},
};
function helloVueFunc() {
const msg = ref("Hello Vue 3");
const exclamationMarkLength = computed(() => {
return msg.value.match(/!/g)?.length || 0;
});
function addExclamationMark() {
msg.value += "!";
}
return {
msg,
addExclamationMark,
exclamationMarkLength,
};
}

若要使用多個函式,可這樣寫:

<div id="app">
<h1>{{msg}}</h1>
<button @click="addExclamationMark()">Add !</button>
<p>Add exclmation mark times: {{exclamationMarkLength}}</p>
<h2>To do List</h2>
<p v-for="(todo, index) in todos" :key="index">{{ todo }}</p>
</div>
<script>
const { ref, computed } = Vue;
const App = {
setup() {
return { ...helloVueFunc(), ...todoListFunc() };
},
};
function helloVueFunc() {
const msg = ref("Hello Vue 3");
const exclamationMarkLength = computed(() => {
return msg.value.match(/!/g)?.length || 0;
});
function addExclamationMark() {
msg.value += "!";
}
return {
msg,
addExclamationMark,
exclamationMarkLength,
};
}
function todoListFunc() {
const todos = ref([
"Buy apples",
"Learn Vue 3",
"Watch It's okay not to be okay",
]);
return {
todos,
};
}
Vue.createApp(App).mount("#app");
</script>

這樣會碰到一個問題,函式太多的時候,很難辨別模板中的物件來自於哪個函式。也可以改成這樣寫:

setup() {
const {
msg,
addExclamationMark,
exclamationMarkLength,
} = helloVueFunc();
const { todos } = todoListFunc();
return { msg, addExclamationMark, exclamationMarkLength, todos };
},

生命週期

若想在 setup 中寫在生命週期中執行的程式碼,可以這樣寫:

const { onBeforeMount, onMounted } = Vue;const App = {
setup() {
onBeforeMount(() => {
console.log("Before Mount!");
});
onMounted(() => {
console.log("Mounted!");
});
};

setup 中無法使用 beforeCreatecreated,是因為 setup 是在 beforeCreate 後立即被呼叫,created 則在 setup 之後,可以直接將程式碼寫在相對的生命週期

watchEffect

假如我有一個 input,當我輸入 input 時需要發出非同步請求

<div id="app"> 
<input type="number" v-model="searchInput" />
searchInput: {{searchInput}}
<ul>
<li v-for="(user, index) in users" :key="index">{{user}}</li>
</ul>
</div>
<script>
const { ref, watchEffect } = Vue;
const App = {
setup() {
const searchInput = ref(1);
const users = ref([]);
usersAPI
.getRandomUsersByNumber(searchInput.value)
.then((usersData) => (users.value = usersData));
return { searchInput, users };
},
};
// usersAPI Obj...Vue.createApp(App).mount("#app");
</script>

會發現 input 不論怎麼更動,users 都只有 setup 時發出請求回傳的值,這時候就可以使用 watchEffect

watchEffect(() => {
usersAPI
.getRandomUsersByNumber(searchInput.value)
.then((usersData) => (users.value = usersData));
});

searchInput 的值改變了,就會觸發 watchEffect 的回呼函式再次發出請求。也可以使用 watch

watch(searchInput, (val) => {
usersAPI
.getRandomUsersByNumber(val)
.then((usersData) => (users.value = usersData));
});

因為 watch 是延遲載入,在 setup 階段不會呼叫回呼函式,若想要在 setup 階段呼叫,可加入 immediate: true,在載入時便會先發出一次請求:

watch(searchInput, (val) => {
usersAPI
.getRandomUsersByNumber(val)
.then((usersData) => (users.value = usersData));
}, {immediate: true});
在載入時便會先發出一次請求。

針對 composition API 的筆記先記錄到這邊,目前仍在學習中,如果內容有任何錯誤在煩請指出,謝謝您

--

--

Eason Lin
Eason Lin

Written by Eason Lin

Frontend Web Developer | Books

No responses yet