ref
概述
生成值類型響應(yīng)式數(shù)據(jù)
通過.value
值修改
生成對象和數(shù)組類型的響應(yīng)式對象選用reactive
方式比較好
html
<template>
<div>
<div>countRef: {{ countRef }}</div>
<div>objCountRef: {{ objCountRef.count }}</div>
<div>愛好: {{ hobbyRef.join('---') }}</div>
</div>
</template>
JavaScript
import { ref } from 'vue';
export default {
name: 'refDemo',
setup () {
// 值類型
const countRef = ref(1);
console.log(countRef);
// 對象
const objCountRef = ref({ count: 1 });
// 數(shù)組
const hobbyRef = ref(['爬山', '游泳']);
setTimeout(() => {
// 通過value改變值
countRef.value = 2;
objCountRef.value.count = 3;
hobbyRef.value.push('吃飯');
}, 3000);
return {
countRef,
objCountRef,
hobbyRef
};
}
}
reactive
概述
reactive
方法根據(jù)傳入的對象,創(chuàng)建返回一個深度響應(yīng)式對象。響應(yīng)式對象看起來和傳入的對象一樣。但是,響應(yīng)式對象屬性值改動,不管層級有多深,都會觸發(fā)響應(yīng)式,新增和刪除屬性也會觸發(fā)響應(yīng)式。
1、改變name
屬性
2、深度改變address
屬性
3、新增school
屬性
4、刪除age
屬性
html
<template>
<div class="demo">
<div>姓名: {{ state.name }}</div>
<div v-if="state.age > 0">年齡: {{ state.age }}</div>
<div>地址: {{ state.address.provoince }} - {{ state.address.city }} - {{ state.address.street }}</div>
</div>
<div class="demo">
<div>學(xué)校: {{ state.school || '自學(xué)成才' }}</div>
</div>
</template>
JavaScript
import { reactive } from 'vue';
export default {
name: 'reactiveDemo',
setup () {
// 響應(yīng)式對象
const state = reactive({
name: '太涼',
age: 18,
hobby: ['游泳', '爬山'],
address: {
provoince: '北京',
city: '北京',
street: '東城區(qū)長安街'
}
});
// 過3秒后改變
setTimeout(() => {
// update1: 改變name屬性
state.name = '冰箱太涼';
state.age = 25;
// update2: 深度改變
state.address.provoince = '山東省';
// address屬性
state.address.city = '臨沂市';
// update3: 新增school屬性
state.school = '清華北大';
// update4: 刪除年齡屬性
delete state.age;
// update5: 數(shù)組添加一項
state.hobby.push('打豆豆');
}, 3000);
return {
// 注意這里不能通過...state方式結(jié)構(gòu),
// 這樣會丟失響應(yīng)式
state
};
}
}
style
.demo {
text-align: left;
width: 600px;
margin: 20px auto;
}
toRef
概述
1、針對一個響應(yīng)式對象(
reactive
封裝)的prop
(屬性)創(chuàng)建一個ref
,且保持響應(yīng)式
2、兩者保持引用關(guān)系
html
<template>
<div class="demo">
<div>姓名--state.name: {{ state.name }}</div>
<div>姓名2--nameRef: {{ nameRef }}</div>
<div>年齡: {{ state.age }}</div>
</div>
</template>
JavaScript
import { reactive, toRef } from 'vue';
export default {
name: 'toRefDemo',
setup () {
// 響應(yīng)式對象
const state = reactive({
name: '太涼',
age: 18
});
// 通過toRef創(chuàng)建一個Ref響應(yīng)式
const nameRef = toRef(state, 'name');
// 過3秒后改變 兩者 保持引用關(guān)系
setTimeout(() => {
// update1: 改變name屬性
state.name = '冰箱太涼';
}, 3000);
// 過6秒后改變兩者保持引用關(guān)系
setTimeout(() => {
// update1: 改變name屬性
nameRef.value = '我就是冰箱太涼';
}, 6000);
return {
nameRef,
state
};
}
}
toRefs
概述
toRefs
是一種用于破壞響應(yīng)式對象并將其所有屬性轉(zhuǎn)換為ref
的實用方法
1、將響應(yīng)式對象(reactive
封裝)轉(zhuǎn)成普通對象
2、對象的每個屬性(prop
)都是對應(yīng)的ref
3、兩者保持引用關(guān)系
html
<template>
<div class="demo">
<h3>state方式不推薦的方式綁定</h3>
<div>姓名--state.name: {{ state.name }}</div>
<div>年齡--state.age: {{ state.age }}</div>
</div>
<div class="demo">
<h3>toRefs之后的方式推薦這種方式,return需要{ ...toRefs(state) }</h3>
<div>姓名--name: {{ name }}</div>
<div>年齡--age: {{ age }}</div>
</div>
</template>
JavaScript
import { reactive, toRefs } from 'vue';
export default {
name: 'toRefsDemo',
setup () {
// 響應(yīng)式對象
const state = reactive({
name: '太涼',
age: 18
});
// 通過toRefs創(chuàng)建一個響應(yīng)式對象屬性的Ref
const toRefsValue = toRefs(state);
// 過3秒后改變 兩者保持引用關(guān)系
setTimeout(() => {
state.name = '冰箱太涼';
state.age = '30';
}, 3000);
// 過6秒后改變 兩者保持引用關(guān)系
setTimeout(() => {
toRefsValue.name.value = '我就是宇宙小超人';
toRefsValue.age.value = '101';
}, 6000);
return {
// 不建議使用這種方式,可以用下面的方式直接替換
state,
// 最佳方式:這里是結(jié)構(gòu)將name的ref,
// age的ref結(jié)構(gòu)到對象根下面
...toRefsValue
};
}
}
使用toRefs(state)方式返回
<template>
<div>
<div>姓名:{{ name }}</div>
<div>年齡:{{ age }}</div>
</div>
</template>
import { reactive, toRefs } from 'vue';
export default {
setup () {
const state = reactive({
age: 20,
name: '太涼'
});
const stateAsRefs = toRefs(state);
return {
...stateAsRefs
};
}
}
ref和reactive使用上區(qū)別
reactive
定義引用數(shù)據(jù)類型,ref
定義基本類型reactive
定義的變量直接使用,ref
定義的變量使用時需要.value
模板中均可直接使用,vue
幫我們判斷了是reactive
還是ref
定義的(通過__v_isRef
屬性),從而自動添加了.value
。
ref和reactive的本質(zhì)區(qū)別
代碼片段壹
源碼細節(jié)較多,本部分只分析關(guān)于
ref
和reactive
的核心代碼
首先找到ref
函數(shù),調(diào)用了createRef
函數(shù),而createRef
返回了RefImpl
類export function ref(value?: unknown) { // 創(chuàng)建ref return createRef(value, false); } function createRef(rawValue: unknown, shallow: boolean) { if (isRef(rawValue)) return rawValue; // 返回一個RefImpl對象 return new RefImpl(rawValue, shallow); }
代碼片段貳
RefImpl
類是不是似曾相識的感覺,沒錯就是Object.defineProperty
,這里做的事情就是收集依賴,觸發(fā)依賴,只是換了個寫法而已。class RefImpl<T> { // 用來保存加工后實現(xiàn)響應(yīng)化的值 private _value: T // 用來保存當(dāng)前未經(jīng)加工過的值 private _rawValue: T // 用來收集依賴,這是一個Set類型 public dep?: Dep = undefined; // 用來標(biāo)識該值是否經(jīng)過ref加工 public readonly __v_isRef = true; constructor(value: T, public readonly __v_isShallow: boolean) { // __v_isShallow默認沒有傳, // 故默認為undefined,這里分別調(diào)用toRaw和toReactive this._rawValue = __v_isShallow ? value : toRaw(value); this._value = __v_isShallow ? value : toReactive(value); } get value() { trackRefValue(this); return this._value; } set value(newVal) { const useDirectValue = this.__v_isShallow || isShallow(newVal) || isReadonly(newVal); newVal = useDirectValue ? newVal : toRaw(newVal); if (hasChanged(newVal, this._rawValue)) { this._rawValue = newVal; this._value = useDirectValue ? newVal : toReactive(newVal); triggerRefValue(this, newVal); } } }
代碼片段叁
toReactive
函數(shù)如果傳入的參數(shù)是一個對象的話,返回值將會調(diào)用reactive
方法來進行包裹,reactive
最終會通過Proxy
來實現(xiàn)響應(yīng)式。export const toReactive = <T extends unknown>(value: T): T => isObject(value) ? reactive(value) : value;
總結(jié)
壹
1、基礎(chǔ)類型值(
String
、Number
、Boolean
或Symbol
)或單值對象(類似{ count: 1 }
這樣只有一個屬性值的對象)使用ref
2、引用類型值(Object
、Array
)使用reactive
貳
reactive
將引用類型值變?yōu)轫憫?yīng)式,使用Proxy
實現(xiàn)ref
可將基本類型和引用類型都變成響應(yīng)式,通過監(jiān)聽類的value
屬性的get
和set
實現(xiàn),但是當(dāng)傳入的值為引用類型時實際上內(nèi)部還是使用reactive
方法進行的處理ref
經(jīng)修改實現(xiàn)方式后性能更高,推薦使用ref
一把梭
叁
1、
ref
創(chuàng)建基本數(shù)據(jù)類型時,是通過vue2
中類似與Object.defineProperty
的做法實現(xiàn)響應(yīng)
2、ref
創(chuàng)建對象時,內(nèi)部調(diào)用的是reactive
方法
3、vue3
中ref
實際是對reactive
的二次封裝增強,reactive
能做的ref
一定能做,所以開發(fā)中多多使用ref
一陣見血的見解
1、
ref
把數(shù)據(jù)封裝成一個整體,重新給數(shù)據(jù)指向新的內(nèi)存地址,并且讓其擁有響應(yīng)式功能。
2、reactive
把引用數(shù)據(jù)的每一個數(shù)據(jù)打散成單個獨立的響應(yīng)式數(shù)據(jù),以便對數(shù)據(jù)的增刪改查操作,也就是深度監(jiān)聽的意思。
3、開發(fā)中如果想重置一個數(shù)組那么建議使用ref
,因為ref
重置了內(nèi)存地址;如果是一個固定數(shù)據(jù)對象,只是想修改數(shù)據(jù)中的某個屬性值,那么使用reactive
比較合適。文章來源:http://www.zghlxwxcb.cn/news/detail-604284.html
坑
在對
ref
和reactive
不是很了解的時候誤用reactive
定義一個空數(shù)組用來存放后端返回的數(shù)據(jù),結(jié)果請求回來的數(shù)據(jù)一直無法正常的在頁面上顯示。
在使用vue3
+typeScript
+elementPlus
+select
實現(xiàn)下拉框選擇時,下拉框的數(shù)據(jù)一直是’無數(shù)據(jù)’狀態(tài),后來使用ref
解決了此問題。文章來源地址http://www.zghlxwxcb.cn/news/detail-604284.html
到了這里,關(guān)于java學(xué)習(xí)路程之篇三、進階知識、面向?qū)ο蟾呒墶⒔涌谛绿匦?、代碼塊、內(nèi)部類、Lambda表達式、窗體、組件、事件的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!