「快速學(xué)習(xí)系列」我熬夜整理了Vue3.x響應(yīng)性API
前言
Vue3.x正式版發(fā)布已經(jīng)快半年了,相信大家也多多少少也用Vue3.x開發(fā)過項目。那么,我們今天就整理下Vue3.x中的響應(yīng)性API。
響應(yīng)性API
reactive
作用:創(chuàng)建一個響應(yīng)式數(shù)據(jù)。
本質(zhì):傳入數(shù)據(jù)(復(fù)雜類型:數(shù)組和json對象)包裝成一個Proxy對象。如果傳入其他對象,默認(rèn)情況下修改對象,界面不會自動更新,如果想更新,可以通過重新賦值(創(chuàng)建一個新的對象)的方式。
<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)建一個響應(yīng)式數(shù)據(jù)。
本質(zhì):(該本質(zhì)寫的不夠嚴(yán)謹(jǐn))針對復(fù)雜類型還是reactive。當(dāng)我們給ref函數(shù)傳遞一個值(一般是簡單類型)之后,ref函數(shù)底層會自動將ref轉(zhuǎn)換成reactive,即ref(123) => reactive({value:123}),所以修改對應(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)建一個響應(yīng)式 proxy,跟蹤其自身 property 的響應(yīng)性,但不執(zhí)行嵌套對象的深度響應(yīng)式轉(zhuǎn)換 (暴露原始值)。
本質(zhì):對于嵌套對象不做響應(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; // 無響應(yīng)性
}
return {
state,
fn,
fn1
}
}
}
</script>
shallowRef
作用:創(chuàng)建一個 ref,它跟蹤自己的 .value 更改,但不會使其值成為響應(yīng)式的。不會將其值轉(zhuǎn)化為Proxy對象。
<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界面不會變。
// 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
作用:獲取一個對象 (響應(yīng)式或純對象) 或 ref 并返回原始 proxy 的只讀 proxy。只讀 proxy 是深層的:訪問的任何嵌套 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)建一個 proxy,使其自身的 property 為只讀,但不執(zhí)行嵌套對象的深度只讀轉(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)式對象轉(zhuǎn)普通對象。
本質(zhì):返回由reactive或 readonly 方法轉(zhuǎn)換成響應(yīng)式代理的普通對象。這是一個還原方法,可用于臨時讀取,訪問不會被代理/跟蹤,寫入時也不會觸發(fā)更改。不建議一直持有原始對象的引用。
<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"}. 值雖改變,但是頁面沒有變化。
}
return {
state,
fn
}
}
}
</script>
markRaw
作用:標(biāo)記一個對象,使其永遠(yuǎn)不會轉(zhuǎn)換為 proxy。返回對象本身。
<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界面不會改變。
}
return{
state,
fn
}
}
}
</script>
toRef
如果使用ref,我們修改響應(yīng)式的數(shù)據(jù)是不會影響到原始數(shù)據(jù)的(復(fù)制)。如果使用toRef,我們修改響應(yīng)式的數(shù)據(jù)是會影響到原始數(shù)據(jù)的(引用)。
作用:可以用來為源響應(yīng)式對象上的 property 新創(chuàng)建一個 ref。然后可以將 ref 傳遞出去,從而保持對其源 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ù)不會發(fā)生改變
console.log(state);
}
// toRef
function fn1(){
state1.value = "345";
console.log(os); // 原始數(shù)據(jù)會發(fā)生改變
console.log(state1);
}
return {
state,
fn,
state1,
fn1
}
}
}
</script>
toRefs
作用:將響應(yīng)式對象轉(zhuǎn)換為普通對象,其中結(jié)果對象的每個 property 都是指向原始對象相應(yīng) property 的ref。
用途:當(dāng)從合成函數(shù)返回響應(yīng)式對象時,toRefs 非常有用,這樣消費(fèi)組件就可以在不丟失響應(yīng)性的情況下對返回的對象進(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
})
// 返回時轉(zhuǎn)換為ref
return toRefs(state)
}
</script>
customRef
作用:創(chuàng)建一個自定義的 ref,并對其依賴項跟蹤和更新觸發(fā)進(jìn)行顯式控制。它需要一個工廠函數(shù),該函數(shù)接收 track 和 trigger 函數(shù)作為參數(shù),并應(yīng)返回一個帶有 get 和 set 的對象。
<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
作用:依賴項變化時,其賦予的值也就相應(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的值也會相應(yīng)改變
// os.value = 26; // Write operation failed: computed value is readonly
}
return{
state,
os,
fn
}
}
}
</script>
watchEffect
作用:在響應(yīng)式地跟蹤其依賴項時立即運(yùn)行一個函數(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)行時會執(zhí)行它,如果響應(yīng)依賴項改變時,會重新執(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)僅在偵聽源發(fā)生更改時調(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>
結(jié)語
謝謝閱讀,希望沒有浪費(fèi)您的時間。可以結(jié)合代碼例子自己敲敲代碼,響應(yīng)性API還有很多用處,這里只介紹了九牛一毛。2021年到來,趕快行動起來吧!
小獅子有話說
你好,我是 Chocolate,一個獅子座的前端攻城獅,希望成為優(yōu)秀的前端博主,每周都會更新文章,與你一起變優(yōu)秀~
關(guān)注 小獅子前端,回復(fù)【小獅子】獲取為大家整理好的文章、資源合集我的博客地址: yangchaoyi.vip歡迎收藏,可在博客留言板留下你的足跡,一起交流~覺得文章不錯,【 點(diǎn)贊】【在看】支持一波 ??ヽ(°▽°)ノ?
叮咚~ 可以給小獅子加
星標(biāo),便于查找。感謝加入小獅子前端,最好的我們最美的遇見,我們下期再見~
