title: Vue3使用Composition API實現響應式 date: 2024/5/29 下午8:10:24 updated: 2024/5/29 下午8:10:24 categories: 前端開發 tags: Vue3 Composition Refs Reactive Watch L ...
title: Vue3使用Composition API實現響應式
date: 2024/5/29 下午8:10:24
updated: 2024/5/29 下午8:10:24
categories:
- 前端開發
tags:
- Vue3
- Composition
- Refs
- Reactive
- Watch
- Lifecycle
- Debugging
1. 介紹
Composition API是Vue.js 3中新增的一組API,用於在組件中組合邏輯和功能。它可以讓你更好地組織和重用代碼,使組件更易於理解和維護。在使用Composition
API時,你可以使用<script setup>
語法或setup()
函數,兩種方式都可以使用Composition API中的響應式API、生命周期鉤子、模板引用和自定義渲染函數等特性。
2. 基本響應式
在Vue.js 3中,Composition API提供了幾種創建響應式數據的方法,包括ref
、reactive
、readonly
、shallowReactive
和shallowReadonly
。
2.1 ref
ref
函數用於創建一個響應式的ref對象,其值可以通過.value
屬性獲取或設置。當ref對象的值發生變化時,Vue.js會自動更新視圖。AD:首頁 | 一個覆蓋廣泛主題工具的高效線上平臺
<template>
<div>
<p>count: {{ count }}</p>
<button @click="increment">+1</button>
</div>
</template>
<script setup>
import { ref } from 'vue';
const count = ref(0);
function increment() {
count.value++;
}
</script>
2.2 reactive
reactive
函數用於創建一個響應式的對象,其所有屬性都是響應式的。當對象的屬性發生變化時,Vue.js會自動更新視圖。
<template>
<div>
<p>name: {{ user.name }}</p>
<p>age: {{ user.age }}</p>
<button @click="incrementAge">+1</button>
</div>
</template>
<script setup>
import { reactive } from 'vue';
const user = reactive({
name: 'Alice',
age: 20
});
function incrementAge() {
user.age++;
}
</script>
2.3 readonly
readonly
函數用於創建一個只讀的響應式對象,其所有屬性都是只讀的。當試圖修改只讀對象的屬性時,會拋出一個錯誤。
<template>
<div>
<p>name: {{ user.name }}</p>
<p>age: {{ user.age }}</p>
</div>
</template>
<script setup>
import { reactive, readonly } from 'vue';
const user = reactive({
name: 'Alice',
age: 20
});
const readonlyUser = readonly(user);
// 會拋出一個錯誤
readonlyUser.age = 21;
</script>
2.4 shallowReactive
shallowReactive
函數用於創建一個淺響應式的對象,其所有屬性都是響應式的,但其子對象的屬性不是響應式的。
AD:專業搜索引擎
<template>
<div>
<p>name: {{ user.name }}</p>
<p>age: {{ user.age }}</p>
<p>address: {{ user.address }}</p>
<button @click="incrementAge">+1</button>
<button @click="changeAddress">改變地址</button>
</div>
</template>
<script setup>
import { shallowReactive } from 'vue';
const user = shallowReactive({
name: 'Alice',
age: 20,
address: {
province: 'Beijing',
city: 'Beijing'
}
});
function incrementAge() {
user.age++;
}
function changeAddress() {
user.address = {
province: 'Shanghai',
city: 'Shanghai'
};
}
</script>
2.5 shallowReadonly
shallowReadonly
函數用於創建一個淺只讀的響應式對象,其所有屬性都是只讀的,但其子對象的屬性不是只讀的。
<template>
<div>
<p>name: {{ user.name }}</p>
<p>age: {{ user.age }}</p>
<p>address: {{ user.address }}</p>
<!-- 會拋出一個錯誤 -->
<button @click="changeAddress">改變地址</button>
</div>
</template>
<script setup>
import { shallowReactive, shallowReadonly } from 'vue';
const user = shallowReactive({
name: 'Alice',
age: 20,
address: {
province: 'Beijing',
city: 'Beijing'
}
});
const readonlyUser = shallowReadonly(user);
// 會拋出一個錯誤
readonlyUser.age = 21;
</script>
3. 響應式API
Composition API提供了幾種響應式API,包括watchEffect
、watch
、computed
和provide/inject
。
3.1 watchEffect
watchEffect
函數用於創建一個響應式的副作用函數,當響應式數據發生變化時,副作用函數會自動重新執行。
<template>
<div>
<p>count: {{ count }}</p>
<button @click="increment">+1</button>
</div>
</template>
<script setup>
import { ref, watchEffect } from 'vue';
const count = ref(0);
watchEffect(() => {
console.log(`count is ${count.value}`);
});
function increment() {
count.value++;
}
</script>
3.2 watch
watch
函數用於創建一個響應式的監聽器,當響應式數據發生變化時,監聽器會自動執行。
<template>
<div>
<p>count: {{ count }}</p>
<button @click="increment">+1</button>
</div>
</template>
<script setup>
import { ref, watch } from 'vue';
const count = ref(0);
watch(count, (newValue, oldValue) => {
console.log(`count changed from ${oldValue} to ${newValue}`);
});
function increment() {
count.value++;
}
</script>
3.3 computed
computed
函數用於創建一個響應式的計算屬性,其值是根據響應式數據計算得出的。當響應式數據發生變化時,計算屬性會自動重新計算。
AD:漫畫首頁
<template>
<div>
<p>count: {{ count }}</p>
<p>doubleCount: {{ doubleCount }}</p>
<button @click="increment">+1</button>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
const count = ref(0);
const doubleCount = computed(() => {
return count.value * 2;
});
function increment() {
count.value++;
}
</script>
3.4 provide/inject
provide
和inject
函數用於在組件樹中傳遞數據。provide
函數用於在父組件中提供數據,inject
函數用於在子組件中註入數據。
<template>
<div>
<ChildComponent />
</div>
</template>
<script setup>
import { provide } from 'vue';
import ChildComponent from './ChildComponent.vue';
provide('message', 'Hello, world!');
</script>
<template>
<div>
<p>{{ message }}</p>
</div>
</template>
<script setup>
import { inject } from 'vue';
const message = inject('message');
</script>
4. 生命周期鉤子
Composition
API提供了幾種生命周期鉤子,包括setup()
、onBeforeMount()
、onMounted()
、onBeforeUpdate()
、onUpdated()
、onBeforeUnmount()
、onUnmounted()
、onErrorCaptured()
、onRenderTracked()
和onRenderTriggered()
。
4.1 setup()
setup()
函數是Composition API的入口點,用於在組件創建之前執行一些初始化操作。
<template>
<div>
<p>count: {{ count }}</p>
<button @click="increment">+1</button>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const count = ref(0);
function increment() {
count.value++;
}
return {
count,
increment
};
}
};
</script>
4.2 onBeforeMount()
onBeforeMount()
函數在組件掛載之前執行。
<template>
<div>
<p>count: {{ count }}</p>
<button @click="increment">+1</button>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const count = ref(0);
function increment() {
count.value++;
}
onBeforeMount(() => {
console.log('before mount');
});
return {
count,
increment
};
}
};
</script>
4.3 onMounted()
onMounted()
函數在組件掛載之後執行。
<template>
<div>
<p>count: {{ count }}</p>
<button @click="increment">+1</button>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const count = ref(0);
function increment() {
count.value++;
}
onMounted(() => {
console.log('mounted');
});
return {
count,
increment
};
}
};
</script>
4.4 onBeforeUpdate()
onBeforeUpdate()
函數在組件更新之前執行。
<template>
<div>
<p>count: {{ count }}</p>
<button @click="increment">+1</button>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const count = ref(0);
function increment() {
count.value++;
}
onBeforeUpdate(() => {
console.log('before update');
});
return {
count,
increment
};
}
};
</script>
4.5 onUpdated()
onUpdated()
函數在組件更新之後執行。
<template>
<div>
<p>count: {{ count }}</p>
<button @click="increment">+1</button>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const count = ref(0);
function increment() {
count.value++;
}
onUpdated(() => {
console.log('updated');
});
return {
count,
increment
};
}
};
</script>
4.6 onBeforeUnmount()
onBeforeUnmount()
函數在組件卸載之前執行。
<template>
<div>
<p>count: {{ count }}</p>
<button @click="increment">+1</button>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const count = ref(0);
function increment() {
count.value++;
}
onBeforeUnmount(() => {
console.log('before unmount');
});
return {
count,
increment
};
}
};
</script>
4.7 onUnmounted()
onUnmounted()
函數在組件卸載之後執行。
<template>
<div>
<p>count: {{ count }}</p>
<button @click="increment">+1</button>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const count = ref(0);
function increment() {
count.value++;
}
onUnmounted(() => {
console.log('unmounted');
});
return {
count,
increment
};
}
};
</script>
4.8 onErrorCaptured()
onErrorCaptured()
函數在組件捕獲到錯誤時執行。
<template>
<div>
<p>count: {{ count }}</p>
<button @click="increment">+1</button>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const count = ref(0);
function increment() {
count.value++;
}
onErrorCaptured((error, instance, info) => {
console.error(error);
return false;
});
return {
count,
increment
};
}
};
</script>
4.9 onRenderTracked
和 onRenderTriggered
onRenderTracked
和onRenderTriggered
是兩個生命周期鉤子,它們與Vue的響應式系統和編譯器有關。這兩個鉤子是在Vue
3.x版本中引入的,主要用於調試目的,幫助開發者瞭解組件渲染過程中的跟蹤和觸發情況。
-
onRenderTracked
鉤子:- 當組件的響應式依賴項被追蹤時,即響應式系統開始跟蹤一個依賴項時,這個鉤子會被調用。
- 它主要用於調試,可以幫助開發者瞭解何時響應式系統開始關註某個依賴項。
onRenderTracked
鉤子接收兩個參數:dep
和context
。dep
是依賴項對象,context
是當前組件的上下文對象。
-
onRenderTriggered
鉤子:- 當組件的響應式依賴項被觸發時,即響應式系統因為某個依賴項的變化而觸發了重新渲染時,這個鉤子會被調用。
- 它主要用於調試,可以幫助開發者瞭解何時響應式系統因為某個依賴項的變化而重新渲染組件。
onRenderTriggered
鉤子也接收兩個參數:dep
和context
,含義與onRenderTracked
相同。
示例代碼:
export default {
setup() {
// 定義一個響應式數據
const count = ref(0);
// 監聽 count 的變化
watch(count, (newValue, oldValue) => {
console.log(`count changed from ${oldValue} to ${newValue}`);
});
// 使用 onRenderTracked 和 onRenderTriggered 進行調試
onRenderTracked((dep, context) => {
console.log(`onRenderTracked: ${dep}`);
});
onRenderTriggered((dep, context) => {
console.log(`onRenderTriggered: ${dep}`);
});
return {
count
};
}
};
在這個示例中,我們定義了一個響應式數據count
,並使用了watch
來監聽它的變化。同時,我們使用了onRenderTracked
和onRenderTriggered
來列印調試信息。當響應式系統開始跟蹤或觸發重新渲染時,我們會得到相應的提示。這些鉤子可以幫助開發者更好地理解Vue組件的渲染過程和響應式系統的運作。