傳送門
Vue3入門到精通-setup
Vue3入門到精通 -reactive 以及reactive相關(guān)函數(shù)
ref 以及 ref相關(guān)函數(shù)
- 將基礎(chǔ)數(shù)據(jù) --> 響應(yīng)式數(shù)據(jù) == 把值類型的數(shù)據(jù)包裝編程響應(yīng)式的引用類型的數(shù)據(jù)都弹。
- 函數(shù)
- 通過(guò)返回值的value屬性獲取響應(yīng)式的值圾亏,修改也需要對(duì).value進(jìn)行修改豺憔。
- 獲取元素
- 在Vue2.x通過(guò)給元素添加 ref ='XXX',然后使用refs.xxx的方式來(lái)獲取元素允跑。
- 在VUe3.x中我們也可以通過(guò)ref來(lái)獲取元素莽使。
創(chuàng)建變量
import { ref } from 'vue'
const count = ref(0)
console.log(count.value) // 0
count.value = 2
console.log(count.value) // 2
在單文件組件中勾笆,不必寫value敌蚜,因?yàn)閟etup方法會(huì)自動(dòng)解析。
<template>
<div>
<span>{{ count }}</span>
<button @click="count ++">Increment count</button>
</div>
</template>
<template>
<div ref="refDiv">我是div</div>
</template>
<script>
import {ref, onMounted} from 'vue';
export default {
name: 'App',
setup() {
let refDiv = ref(null);
onMounted(()=>{
console.log('onMounted',refDiv.value);
// onMounted <div style="color: red;">我是div</div>
refDiv.value.style.color="red"
// 字體顏色變成紅色
});
// setup 生命周期在mounted之前
console.log(refDiv.value);
// null
return {refDiv};
}
}
</script>
?和??區(qū)別
- ref是把值類型添加一層包裝窝爪,使其變成響應(yīng)式的引用類型的值弛车。
- reactive 則是將引用類型的值變成響應(yīng)式的值齐媒。
- : 是否需要添加一層引用包裝。
- 本質(zhì)上: ref(0) 等價(jià)于 reactive({value:0})
ref 對(duì)于
- ref - 創(chuàng)建出來(lái)的數(shù)據(jù) 和以前無(wú)關(guān)(復(fù)制)與js中的 基本類型 表現(xiàn)一致
let a = 1;
let aRef = ref(a);
console.log(a, aRef.value); // 1 1
a = 2;
console.log(a, aRef.value); // 2 1
aRef.value = 3;
console.log(a, aRef.value); // 2 3
ref 對(duì)于
- ref-創(chuàng)建出來(lái)的數(shù)據(jù)和以前相關(guān)(引用) 與js中的 引用數(shù)據(jù)類型 表現(xiàn)一致
let obj = { name: "1" };
let stateRef = ref(obj);
console.log("obj", obj.name);
console.log("ref", stateRef.value.name);
// obj 1
// ref 1
stateRef.value.name = '2';
console.log("obj", obj.name);
console.log("ref", stateRef.value.name);
// obj 2
// ref 2
obj.name='3'
console.log("obj", obj.name);
console.log("ref", stateRef.value.name);
// obj 3
// ref 3
相關(guān)API
作用
- 判斷是否都是ref對(duì)象
- 其實(shí)內(nèi)部是判斷數(shù)據(jù)對(duì)象上是否包含__v_isRef 屬性并且其值為 true纷跛。
用法
const a = ref(a)
const b = 'b'
cosnole.log(isRef(a)) // true
console.log(isRef(b)) // false
- 如果參數(shù)為 ref喻括,則返回內(nèi)部值,否則返回參數(shù)本身贫奠。這是 val = isRef(val) ? val.value : val唬血。
// isRef 判斷是否為ref對(duì)象
const info = ref({name :'名字',info:{age:18,height:1111,}})
const infos = {name :'名字',info:{age:18,height:1111, }}
console.log(isRef(info)) // true
console.log(isRef(infos)) // false
console.log(unref(info)) // Proxy {name: '名字', info: {…}}
console.log(unref(infos))// {name: '名字', info: {…}}
- isRef(info) ? info.value : 'info' 等同unref(info)
作用
- 將 引用數(shù)據(jù)類型 轉(zhuǎn)換為 ref 數(shù)據(jù)類型。
- 將 reactive 數(shù)據(jù)類型轉(zhuǎn)換為 ref 數(shù)據(jù)類型唤崭。
用法
引用數(shù)據(jù)類型
let obj = { name: "syl", age: "123" };
let stateToref = toRef(obj, "name"); // 將name拿出來(lái)
stateToref.value = "zs";
console.log("obj", obj.name);
console.log("ref", stateToref.value);
// obj zs
// ref zs
obj.name = "ls";
console.log("obj", obj.name);
console.log("ref", stateToref.value);
// obj ls
// ref ls
reactive 數(shù)據(jù)類型
let obj = reactive({ name: "syl", age: "123" });
let stateToref = toRef(obj, "name"); // 將name拿出來(lái)
stateToref.value = "zs";
console.log("obj", obj.name);
console.log("ref", stateToref.value);
// obj zs
// ref zs
obj.name = "ls";
console.log("obj", obj.name);
console.log("ref", stateToref.value);
// obj ls
// ref ls
案例1
<p>toref----------{{ stateToref }}</p> // 這里顯示的是zs
let obj = { name: "syl" };
let stateToref = toRef(obj, "name");
stateToref.value = "zs";
console.log("obj", obj.name);
console.log("ref", stateToref.value);
// obj zs
// ref zs
案例2
<p>toref----------{{ stateToref }}</p>
<button @click="changeToref">changeToref</button>
let obj = { name: "syl" };
let stateToref = toRef(obj, "name");
function changeToref() {
stateToref.value = "ls";
console.log("obj", obj.name);
console.log("toref", stateToref.value);
}
// 點(diǎn)擊changeToref拷恨,頁(yè)面沒(méi)有任何變化,仍然顯示syl
// console的結(jié)果是
// obj ls
// toref ls
一個(gè)有意思的案例
<p>toref----------{{ stateToref }}</p>
<p>temp----------{{ temp }}</p>
<button @click="changeToref">changeToref</button>
let obj = { name: "syl" };
let stateToref = toRef(obj, "name");
let temp = ref("我是ref");
function changeToref() {
temp.value = "我是ref我改變啦谢肾!";
stateToref.value = "ls";
}
// 點(diǎn)擊按鈕腕侄,頁(yè)面的ui從
toref----------syl
temp----------我是ref
// 變成
oref----------ls
temp----------我是ref我改變啦!
這里可以看到ref觸發(fā)了ui更新勒叠,導(dǎo)致toref的值也進(jìn)行了更新
其實(shí)不把這個(gè)ref的更新寫到這個(gè)函數(shù)里面兜挨,比如新建函數(shù),也會(huì)導(dǎo)致這個(gè)現(xiàn)象
這個(gè)現(xiàn)象對(duì)其他函數(shù)也出現(xiàn)眯分,例如shallowRef拌汇。
作用
批量轉(zhuǎn)換。將響應(yīng)式對(duì)象轉(zhuǎn)換為普通對(duì)象,會(huì)將傳入對(duì)象的每個(gè)屬性處理為 ref 的值弊决。
官方例子
- 當(dāng)從合成函數(shù)返回響應(yīng)式對(duì)象時(shí)噪舀,toRefs 非常有用,這樣消費(fèi)組件就可以在不丟失響應(yīng)性的情況下對(duì)返回的對(duì)象進(jìn)行分解/擴(kuò)散:
function useFeatureX() {
const state = reactive({
foo: 1,
bar: 2
})
// 返回時(shí)轉(zhuǎn)換為ref
return toRefs(state)
}
export default {
setup() {
// 可以在不失去響應(yīng)性的情況下破壞結(jié)構(gòu)
const { foo, bar } = useFeatureX()
return {
foo,
bar
}
}
}
與
創(chuàng)建一個(gè) ref飘诗,它跟蹤自己的 更改与倡,但不會(huì)使其值成為響應(yīng)式的。也就是對(duì) 進(jìn)行更新
才會(huì)觸發(fā)頁(yè)面的更新昆稿,但是如果是一個(gè)引用數(shù)據(jù)類型纺座,只對(duì)改引用數(shù)據(jù)進(jìn)行值的修改,但不會(huì)觸發(fā)更新溉潭。
基本數(shù)據(jù)類型
<p>{{ state1 }}</p>
<button @click="myFn1">基本數(shù)據(jù)類型</button>
let state1 = shallowRef(1);
function myFn1() {
state1.value = 2;
}
// 點(diǎn)擊按鈕净响,頁(yè)面會(huì)顯2
// 也就是對(duì)value進(jìn)行修改可以觸發(fā)頁(yè)面更新
引用數(shù)據(jù)類型
<p>{{ state.a }}</p>
<p>{{ state.b.c }}</p>
<button @click="myFn1">引用數(shù)據(jù)類型-直接修改value</button>
<button @click="myFn2">引用數(shù)據(jù)類型-對(duì)數(shù)據(jù)進(jìn)行修改</button>
let state = shallowRef({
a: "a",
b: {
c: "c",
},
});
function myFn1() {
state.value={
a: "a-new",
b: {
c: "c-new",
},
}
}
// 點(diǎn)擊mufun1 頁(yè)面從
a
c
// 變成
a-new
c-new
// 由此可以看出直接對(duì)value進(jìn)行修改可以觸發(fā)頁(yè)面更新
function myFn2() {
state.value.a = "1";
state.value.b.c = "1";
console.log(state.value.a , state.value.b.c )
}
// 點(diǎn)擊mufun2 頁(yè)面仍然顯示
a
c
// console的結(jié)果是1 1
通常與shallowRef 一起使用喳瓣,主要是主動(dòng)觸發(fā)界面更新的
參數(shù)是ref變量
<p>{{ state.a }}</p>
<p>{{ state.b.c }}</p>
<button @click="myFn2">使用triggerRef</button>
let state = shallowRef({
a: "a",
b: {
c: "c",
},
});
function myFn2() {
state.value.a = "1";
state.value.b.c = "1";
triggerRef(state);
}
// 點(diǎn)擊mufun2 頁(yè)面變成
1
1
自定義ref
返回一個(gè)ref對(duì)象,可以顯式地控制依賴追蹤和觸發(fā)響應(yīng)
<template>
<div>
<p>{{age}}</p>
<button @click="myFn">按鈕</button>
</div>
</template>
import {ref, customRef} from 'vue';
function myRef(value) {
return customRef((track, trigger)=>{
return {
get(){
track(); // 告訴Vue這個(gè)數(shù)據(jù)是需要追蹤變化的
console.log('get', value);
return value;
},
set(newValue){
console.log('set', newValue);
value = "我的年齡==="+newValue;
trigger(); // 告訴Vue觸發(fā)界面更新
}
}
});
}
setup() {
// let age = ref(18); // reactive({value: 18})
let age = myRef(18);
function myFn() {
age.value += 1;
}
return {age, myFn}
}
}
// 頁(yè)面顯示的是18
// 點(diǎn)擊button按鈕后馋贤,變成了我的年齡===19
// 注意點(diǎn):
// 不能在get方法中發(fā)送網(wǎng)絡(luò)請(qǐng)求