iT邦幫忙

2025 iThome 鐵人賽

DAY 4
0
Vue.js

Vue3.6 的革新:深入理解 Composition API系列 第 4

Day 4: Composition API 概述

  • 分享至 

  • xImage
  •  

Composition API 是一組以「函式 + reactive 原語」為核心的 API,它透過 函式 + reactive 原語 的方式,讓使用者用更彈性、可抽換的方式來組合狀態與邏輯,取代過去 Options API(data/ methods/ computed…)「依功能分散」的寫法。

Options API 與 Composition API 的比較


Options API

基礎架構建立在物件的語法,所以邏輯分散在 datamethodscomputedmounted 等不同區塊,可能導致元件變得難以管理,維護困難。

  const app = Vue.createApp({
      data() {
          return {
              count: 0
          }
      },
      methods: {
          increment() {
              this.count++;
          }
      },
      mounted() {
          console.log("Component mounted.");
      }
  });

Composition API

Composition API 是 Vue 3 引入的功能,讓開發者能夠更靈活地組織和管理邏輯。

它的核心組件包括 setup()reactive()ref()computed()watch() 和生命周期方法如 onMounted。此外,還有 provide/ inject 語法來共享狀態。開發者可以使用 composables 提取邏輯復用。

基於函式的語法,可以使用 setup 函式整合所需的邏輯,提升程式碼的可重用性和組織性,更加靈活,尤其適合大型專案。

<script setup lang="ts">
import { ref, onMounted } from 'vue'

const count = ref<number>(0)
const increment = () => count.value++

onMounted(() => {
  console.log("Component mounted.")
})
</script>

<template>
  <button @click="increment">count: {{ count }}</button>
</template>

Composition API 和 Options API 主要的區別在於其 組織邏輯 的方式。Composition API 把功能邏輯封裝在函式中,也就是 composable,例如 useFetch,而 Options API 則是將邏輯分散在 datamethods 等選項中。

使用 Composition API 可提升代碼的可維護性,特別是當應用程式規模擴大的時候,但是它可能對剛接觸 Vue 的開發者來說較為複雜。

最佳實踐:

  • 使用 useXxx 類命名的 composables,避免複雜的解構賦值問題。
  • 當使用觀察者 watchers 監控的時後,要謹慎處理副作用。
  • script setup 中利用 macro 來提升效率,並運用 TypeScript 增加程式碼嚴謹度,接下來會直接做詳細介紹。

瞭解 setup 函式的功能


setup 函式是 Composition API 的核心,以下是其主要功能:

  1. 初始化響應式狀態: 可以使用 refreactive 建立響應式資料。
  2. 定義計算屬性: 使用 computed 定義基於響應式狀態的計算屬性。
  3. 使用生命週期鉤子: 可以直接在 setup 中使用生命週期鉤子,如 onMountedonUnmounted 等。
  4. 返回可用的資料和方法:在 <script setup> 不需要 return,變數直接可用於 template。

以下是範例是一個計數器,從上而下逐一說明前面所描述的 4 個功能:

<script setup lang="ts">
import { ref, onMounted } from 'vue'

const count = ref<number>(0)
const message = ref<string>('Hello, Vue 3.5!')

const increment = () => count.value++
const reset = () => (count.value = 0)

onMounted(() => {
  console.log("Component mounted. Current count:", count.value)
})
</script>

<template>
  <p>{{ message }}</p>
  <p>Count: {{ count }}</p>
  <button @click="increment">Increment</button>
  <button @click="reset">Reset</button>
</template>

核心積木(Reactive 原語與生命週期)


1-setup()<script setup>

  • setup(props, context) 是元件在建立前執行的入口,回傳的東西會暴露給 template。
  • SFC 推薦直接用 <script setup>:更精簡、較佳的 TS 推斷、支援編譯期巨集。
<!-- Counter.vue -->
<script setup lang="ts">
import { ref, computed } from 'vue'

const count = ref(0)                 // 單一原始值/物件的響應式包裝
const double = computed(() => count.value * 2)

function inc() {
  count.value++
}
</script>

<template>
  <button @click="inc">count: {{ count }} / double: {{ double }}</button>
</template>

2-ref vs reactive

  • ref(value):包裝單一值(number / string / boolean / Date / Object 都可),以 .value 取用;在 template 會自動解包
  • reactive(object):把物件/陣列轉為深層響應式 代理,解構時會失去響應,後續介紹響應式的時候會再細說這個坑。

補充常用變體:

  • toRef(obj, key) / toRefs(obj):把 reactive 物件的屬性轉成 ref,避免解構失去響應。
  • shallowRef / shallowReactive:只有最外層響應。
  • markRaw(obj):標記成非響應,常用於大型第三方物件。

3-衍生值與監聽

  • computed(getter):快取的衍生值,依賴變更才重新計算。
  • watch(source, (newVal, oldVal) => { … }, options)精準監聽某個/某些來源(refgetter、或陣列來源)。
  • watchEffect(() => { … })自動收集依賴的副作用,聲明式、快速,但不可拿到 oldVal。

常見 watch 選項:

  • { immediate: true } 初次就跑
  • { deep: true } 深層監聽物件
  • { flush: 'post' } 在 DOM 更新後觸發(避免閃爍/量測時機)

4-生命週期

setup() 內用對應的 hook:

  • onMountedonUpdatedonUnmounted
  • onBeforeMountonBeforeUpdateonBeforeUnmount
  • 以及 onActivated / onDeactivated(keep-alive 場景)

5-Template Refs(DOM/子元件引用)

<script setup lang="ts">
import { ref, onMounted } from 'vue'

const inputEl = ref<HTMLInputElement | null>(null)

onMounted(() => {
  inputEl.value?.focus()
})
</script>

<template>
  <input ref="inputEl" />
</template>

6-provide / inject(跨層傳遞)

用於跨多層傳遞共享狀態,而不必層層 props:

<!-- 父元件 -->
<script setup lang="ts">
import { ref, provide } from 'vue'
provide('theme', ref<'light' | 'dark'>('light'))
</script>

<!-- 子元件 -->
<script setup lang="ts">
import { inject, type Ref } from 'vue'
const theme = inject<Ref<'light' | 'dark'>>('theme')!
</script>

<script setup> 的編譯期巨集(macros)


僅在 SFC 的 <script setup> 可用,由編譯器處理(不是執行期函式)。

  • defineProps<T>():宣告 props 型別
  • defineEmits<...>():宣告事件
  • defineExpose():控制對父層暴露的內容
  • withDefaults(defineProps<...>(), defaults):給 props 預設值
  • defineSlots<...>():型別標註 slots
  • defineModel():更簡捷地定義 v-model(Vue 3.3+)

上一篇
Day 3: 環境設定 - 使用 Vite 的準備工作建立首個 Vue 3 專案
系列文
Vue3.6 的革新:深入理解 Composition API4
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言