「快速學(xué)習(xí)系列」我熬夜整理了Vue3.x響應(yīng)性API
前言
Vue3.x正式版發(fā)布已經(jīng)快半年了,相信大家也多多少少也用Vue3.x開發(fā)過(guò)項(xiàng)目。那么,我們今天就整理下Vue3.x中的響應(yīng)性API。
響應(yīng)性API
reactive
作用: 創(chuàng)建一個(gè)響應(yīng)式數(shù)據(jù)。
本質(zhì): 傳入數(shù)據(jù)(復(fù)雜類型:數(shù)組和json對(duì)象)包裝成一個(gè)Proxy對(duì)象。如果傳入其他對(duì)象,默認(rèn)情況下修改對(duì)象,界面不會(huì)自動(dòng)更新,如果想更新,可以通過(guò)重新賦值(創(chuàng)建一個(gè)新的對(duì)象)的方式。
<template>
<div class="reactive">
<button @click="fn">點(diǎn)擊</button>
<p>{{ state }}</p>
<button @click="fn1">點(diǎn)擊1</button>
<p>{{ timeState }}</p>
</div>
</template>
<script>
import { reactive } from "vue";
export default {
name: "Reactive",
setup() {
let state = reactive({
name: "123",
});
function fn() {
console.log(state);
state.name = "456";
}
let timeState = reactive({
time: new Date(),
});
function fn1() {
const newTime = new Date(timeState.time.getTime());
newTime.setDate(timeState.time.getDate() + 1);
timeState.time = newTime;
console.log(timeState.time);
}
return {
state,
fn,
timeState,
fn1,
};
},
};
</script>
ref
作用: 創(chuàng)建一個(gè)響應(yīng)式數(shù)據(jù)。修改對(duì)應(yīng)的值必須在后面加上.value。
注意點(diǎn): 在template標(biāo)簽內(nèi)不用加.value。
<template>
<div>
<button @click="fn">點(diǎn)擊</button>
<p>{{state}}</p>
<button @click="fn1">點(diǎn)擊1</button>
<p>{{arrState}}</p>
</div>
</template>
<script>
import {ref} from "vue";
export default {
name:"Ref",
setup(){
let state = ref(123);
function fn () {
state.value = 345;
}
let arrState = ref([]);
function fn1 (){
arrState.value.push("1");
}
return {
state,
fn,
arrState,
fn1
}
}
}
</script>
shallowReactive
作用: 創(chuàng)建一個(gè)響應(yīng)式 proxy,跟蹤其自身 property的響應(yīng)性,但不執(zhí)行嵌套對(duì)象的深度響應(yīng)式轉(zhuǎn)換 (暴露原始值)。
本質(zhì): 對(duì)于嵌套對(duì)象不做響應(yīng),值跟蹤自身的第一層property。
<template>
<div>
<button @click="fn">點(diǎn)擊</button>
<button @click="fn1">點(diǎn)擊1</button>
<p>{{state}}</p>
</div>
</template>
<script>
import { shallowReactive } from "vue"
export default {
name:"ShallowReactive",
setup(){
let state = shallowReactive({
name:"maomin",
age:{
number:20
}
})
function fn(){
state.name = "123"; // 響應(yīng)性
}
function fn1(){
state.age.number = 23; // 無(wú)響應(yīng)性
}
return {
state,
fn,
fn1
}
}
}
</script>
shallowRef
作用: 創(chuàng)建一個(gè) ref,它跟蹤自己的.value 更改,但不會(huì)使其值成為響應(yīng)式的。不會(huì)將其值轉(zhuǎn)化為Proxy對(duì)象。
<template>
<div>
<button @click="fn">點(diǎn)擊</button>
<p>{{ state }}</p>
<button @click="fn1">點(diǎn)擊1</button>
<p>{{ state1 }}</p>
</div>
</template>
<script>
import {
shallowRef,
ref,
// triggerRef
} from "vue";
export default {
name: "ShallowRef",
setup() {
let state = shallowRef({
name: "maomin",
});
let state1 = ref({});
function fn() {
state.value.name = "345";
console.log(state.value); // {name: "345"}, 但是UI界面不會(huì)變。
// triggerRef(state); // 如果想觸發(fā)UI界面,可以使用它。
}
function fn1() {
state1.value = {
name: "123",
};
// eslint-disable-next-line no-irregular-whitespace
console.log(state1.value); // Proxy {name: "123"}
}
return {
state,
fn,
state1,
fn1,
};
},
};
</script>
readonly
作用: 獲取一個(gè)對(duì)象 (響應(yīng)式或純對(duì)象) 或 ref 并返回原始 proxy的只讀 proxy。只讀 proxy是深層的:訪問(wèn)的任何嵌套 property也是只讀的。
<template>
<div>
<button @click="fn">點(diǎn)擊</button>
<p>{{os}}</p>
<p>{{state}}</p>
</div>
</template>
<script>
import {reactive, readonly} from "vue";
export default {
name:"Readonly",
setup(){
let state = reactive({
name:"maomin",
age:{
number:18
}
})
let os = readonly(state);
function fn(){
os.name = "123";
}
return{
os,
state,
fn
}
}
}
</script>
shallowReadonly
作用: 創(chuàng)建一個(gè)proxy,使其自身的 property為只讀,但不執(zhí)行嵌套對(duì)象的深度只讀轉(zhuǎn)換 (暴露原始值)。
<template>
<div>
<button @click="fn">點(diǎn)擊</button>
<p>{{os}}</p>
<p>{{state}}</p>
</div>
</template>
<script>
import {
reactive,
shallowReadonly,
isReadonly
} from "vue";
export default {
name:"ShallowReadonly",
setup(){
let state = reactive({
name:"maomin",
age:{
number:18
}
})
let os = shallowReadonly(state);
function fn(){
console.log(isReadonly(os.name)) //false
os.age.number = 20;
}
return{
state,
os,
fn,
}
}
}
</script>
toRaw
作用: 響應(yīng)式對(duì)象轉(zhuǎn)普通對(duì)象。
本質(zhì): 返回由reactive或 readonly 方法轉(zhuǎn)換成響應(yīng)式代理的普通對(duì)象。這是一個(gè)還原方法,可用于臨時(shí)讀取,訪問(wèn)不會(huì)被代理/跟蹤,寫入時(shí)也不會(huì)觸發(fā)更改。不建議一直持有原始對(duì)象的引用。
<template>
<div>
<button @click="fn">點(diǎn)擊</button>
<p>{{state}}</p>
</div>
</template>
<script>
import { reactive, toRaw } from "vue";
export default {
name:"ToRaw",
setup(){
const obj = {
name:"maomin"
};
let state = reactive(obj);
function fn(){
console.log(toRaw(state) === obj); //true
let obj1 = toRaw(state);
obj1.name = "123";
// eslint-disable-next-line no-irregular-whitespace
console.log(state); // Proxy {name: "123"}. 值雖改變,但是頁(yè)面沒(méi)有變化。
}
return {
state,
fn
}
}
}
</script>
markRaw
作用: 標(biāo)記一個(gè)對(duì)象,使其永遠(yuǎn)不會(huì)轉(zhuǎn)換為 proxy。返回對(duì)象本身。
<template>
<div>
<button @click="fn">點(diǎn)擊</button>
<p>{{state}}</p>
</div>
</template>
<script>
import {markRaw,reactive} from "vue"
export default {
name:"MarkRaw",
setup(){
let obj = {name:'maomin', age: 20};
obj = markRaw(obj);
let state = reactive(obj);
function fn(){
state.name = '123';
console.log(state); //這里雖然打印出name:123,但是UI界面不會(huì)改變。
}
return{
state,
fn
}
}
}
</script>
toRef
如果使用ref,我們修改響應(yīng)式的數(shù)據(jù)是不會(huì)影響到原始數(shù)據(jù)的(復(fù)制)。
如果使用toRef,我們修改響應(yīng)式的數(shù)據(jù)是會(huì)影響到原始數(shù)據(jù)的(引用)。
作用: 可以用來(lái)為源響應(yīng)式對(duì)象上的 property新創(chuàng)建一個(gè)ref。然后可以將 ref傳遞出去,從而保持對(duì)其源 property的響應(yīng)式連接。
<template>
<div>
<button @click="fn">點(diǎn)擊</button>
<p>{{state}}</p>
<button @click="fn1">點(diǎn)擊1</button>
<p>{{state1}}</p>
</div>
</template>
<script>
import {reactive, ref, toRef} from "vue"
export default {
name:"ToRef",
setup(){
let obj = {name:"maomin"};
let os = reactive(obj);
let state = ref(os.name);
let state1 = toRef(os,'name');
// ref
function fn(){
state.value = "123";
console.log(os); // 原始數(shù)據(jù)不會(huì)發(fā)生改變
console.log(state);
}
// toRef
function fn1(){
state1.value = "345";
console.log(os); // 原始數(shù)據(jù)會(huì)發(fā)生改變
console.log(state1);
}
return {
state,
fn,
state1,
fn1
}
}
}
</script>
toRefs
作用: 將響應(yīng)式對(duì)象轉(zhuǎn)換為普通對(duì)象,其中結(jié)果對(duì)象的每個(gè) property 都是指向原始對(duì)象相應(yīng) property 的ref。
用途: 當(dāng)從合成函數(shù)返回響應(yīng)式對(duì)象時(shí),toRefs 非常有用,這樣消費(fèi)組件就可以在不丟失響應(yīng)性的情況下對(duì)返回的對(duì)象進(jìn)行分解/擴(kuò)散。
<template>
<div>
<button @click="fn">點(diǎn)擊</button>
<p>{{state}}</p>
<button @click="fn1">點(diǎn)擊1</button>
<p>{{foo}}</p>
</div>
</template>
<script>
import {reactive, toRefs} from "vue"
export default {
name:"ToRefs",
setup(){
let obj = {
name:"maomin",
age:20
}
let os = reactive(obj);
let state = toRefs(os);
function fn(){
state.name.value = "123";
os.name = "234";
console.log(os);
console.log(state);
console.log(state.name.value === os.name); //true
}
const { foo, bar } = useFeatureX();
function fn1(){
foo.value = "2";
}
return {
fn,
state,
foo,
bar,
fn1
}
}
}
function useFeatureX() {
const state = reactive({
foo: 1
})
// 返回時(shí)轉(zhuǎn)換為ref
return toRefs(state)
}
</script>
customRef
作用: 創(chuàng)建一個(gè)自定義的ref,并對(duì)其依賴項(xiàng)跟蹤和更新觸發(fā)進(jìn)行顯式控制。它需要一個(gè)工廠函數(shù),該函數(shù)接收 track 和 trigger 函數(shù)作為參數(shù),并應(yīng)返回一個(gè)帶有 get 和 set 的對(duì)象。
<template>
<div>
<button @click="fn">點(diǎn)擊</button>
<p>{{state}}</p>
</div>
</template>
<script>
import {customRef} from "vue";
function myRef(value){
return customRef((track, trigger)=>{
return {
get(){
track();
console.log('get',value);
return value;
},
set(newValue){
console.log('set',newValue);
value = newValue;
trigger();
}
}
})
}
export default {
name:"CustomRef",
setup(){
let state = myRef(18);
function fn(){
state.value = 19;
}
return {
state,
fn
}
}
}
</script>
computed
作用: 依賴項(xiàng)變化時(shí),其賦予的值也就相應(yīng)改變。
注意點(diǎn): 直接修改computed是不可以的。
<template>
<div>
<p>{{state}}</p>
<p>{{os}}</p>
<button @click="fn">點(diǎn)擊</button>
</div>
</template>
<script>
import {computed,ref} from "vue"
export default {
name: "Computed",
setup(){
let state = ref(12);
let os = computed(() => state.value + 1);
function fn(){
state.value = 23; // os的值也會(huì)相應(yīng)改變
// os.value = 26; // Write operation failed: computed value is readonly
}
return{
state,
os,
fn
}
}
}
</script>
watchEffect
作用: 在響應(yīng)式地跟蹤其依賴項(xiàng)時(shí)立即運(yùn)行一個(gè)函數(shù),并在更改依賴項(xiàng)時(shí)重新運(yùn)行它。
<template>
<div>
<button @click="fn">點(diǎn)擊</button>
<p>{{state}}</p>
<p>{{state1}}</p>
<p>{{num}}</p>
</div>
</template>
<script>
import { reactive, ref, watchEffect } from "vue"
export default {
name:"WatchEffect",
setup(){
let state = ref(0);
let state1 = reactive({
name:"maomin"
})
let num = 1;
// 首次運(yùn)行時(shí)會(huì)執(zhí)行它,如果響應(yīng)依賴項(xiàng)改變時(shí),會(huì)重新執(zhí)行它。
watchEffect(()=>{
// console.log(num);
console.log(state.value);
console.log(state1);
})
function fn() {
state.value = 3;
state1.name = "123";
num = 2;
}
return{
fn,
state,
state1,
num
}
}
}
</script>
watch
作用: 默認(rèn)情況下,它也是惰性的——即回調(diào)僅在偵聽(tīng)源發(fā)生更改時(shí)調(diào)用。
<template>
<div>
<button @click="fn">點(diǎn)擊</button>
<p>{{state}}</p>
<button @click="fn1">點(diǎn)擊1</button>
<p>{{state1}}</p>
</div>
</template>
<script>
import {reactive, ref, watch} from "vue"
export default {
name:"Watch",
setup(){
// reactive
let state = reactive({
name:"maomin"
})
watch(
() => state.name,
(count) =>{
console.log(count); //123
}
)
function fn() {
state.name = "123";
}
//ref
let state1 = ref(1);
watch(
state1,
(count) =>{
console.log(count); //2
}
)
function fn1() {
state1.value = 2;
}
return {
state,
fn,
fn1,
state1
}
}
}
</script>
作者:Vam的金豆之路
主要領(lǐng)域:前端開發(fā)
我的微信:maomin9761
微信公眾號(hào):前端歷劫之路