Vue3官方文檔中定義響應式數據使用ref()或者reactive()
一、ref的研究
1)ref創建一個響應式數據,一般來說用於創建簡單類型的響應式對象,比如String
、Number、boolean
類型;
2)當我們給ref傳遞一個值之后,如果使用的是基本類型響應式依賴Object.defineProperty( )的get( )和set( ),如果ref使用的是引用類型,ref函數底層會自動將ref轉換成reactive; ref(18) => reactive({value:18});
3)需要注意的是ref定義的值在Vue中使用直接使用所定義的字段,但是在js中獲取或者修改值需要通過value;
4)ref也可以創建引用類型,對於復雜的對象,值是一個被proxy
攔截處理過的對象,但是里面的屬性不是RefImpl
類型的對象,proxy
代理的對象同樣被掛載到value
上,所以可以通過obj.value.key
來讀取屬性,這些屬性同樣也是響應式的,更改時可以觸發視圖的更新
具體使用及結構打印如下:
1 <template> 2 <h3>{{ refBaseType }}</h3> 3 <h3>{{ refReferenceType }}</h3> 4 </template> 5 6 <script setup> 7 import { ref } from 'vue' 8 let refBaseType = ref(null) 9 //ref 需要用.value去獲取值 10 refBaseType.value = 'i am ref' 11 console.log('refBaseType', refBaseType) 12 //打印結果 13 /* 14 RefImpl {_shallow: false, dep: undefined, __v_isRef: true, _rawValue: "i am ref", _value: "i am ref"} 15 dep: undefined 16 __v_isRef: true 17 _rawValue: "i am ref" 18 _shallow: false 19 _value: "i am ref" 20 value: "i am ref" 21 __proto__: Object 22 * */ 23 //如果ref使用的是對象,底層ref會借助reactive的proxy ****** 24 let refReferenceType = ref({}) 25 refReferenceType.value = { count: 1 } 26 console.log('refReferenceType', refReferenceType) 27 //打印結果 28 /* 29 RefImpl {_shallow: false, dep: undefined, __v_isRef: true, _rawValue: {…}, _value: Proxy} 30 dep: Set(1) {ReactiveEffect} 31 __v_isRef: true 32 _rawValue: {count: 1} 33 _shallow: false 34 _value: Proxy {count: 1} 35 value: Proxy //如果ref使用的是對象,底層ref會借助reactive的proxy 36 [[Handler]]: Object 37 [[Target]]: Object 38 [[IsRevoked]]: false 39 40 * */ 41 </script>
二、reactive研究
1)reactive里面參數定義必須是對象或者數組(json/arr),本質將傳入的數據包裝成proxy對象;
2)基於Es6的Proxy實現,通過Reflect反射代理操作源對象,相比於reactive定義的淺層次響應式數據對象,reactive定義的是更深層次的響應式數據對象;
3)
1 <template> 2 <h3>{{ reactiveBaseType }}</h3> 3 <h3>{{ reactiveReferenceType }}</h3> 4 <div @click="setData">setData</div> 5 <div @click="setReactive">setReactive</div> 6 </template> 7 8 <script setup> 9 import { reactive } from 'vue' 10 let reactiveBaseType = reactive(null) 11 //reactive 無法定義基本類型的proxy,且設置值無法響應數據 12 let setData = () => { 13 reactiveBaseType = 'fai' 14 } 15 console.log('reactiveBaseType', reactiveBaseType) 16 //打印結果 17 /* 18 null 19 * */ 20 //如果reactive使用的是引用類型 21 let reactiveReferenceType = reactive({ count: 1 }) 22 let setReactive = () => { 23 //這樣設置會去proxy 24 reactiveReferenceType = { count: 1 } 25 console.log(reactiveReferenceType) 26 //打印結果 27 /* 28 *{count: 1} //proxy 沒了,所以reactive申明的無法直接替換整個對象,如果有這個需求請使用ref 29 * */ 30 } 31 console.log('reactiveReferenceType', reactiveReferenceType) 32 //打印結果 33 /* 34 //proxy響應式 35 Proxy {count: 1} 36 [[Handler]]: Object 37 [[Target]]: Object 38 count: 1 39 __proto__: Object 40 [[IsRevoked]]: false 41 * */ 42 </script> 43 44 <style lang="scss" scoped> 45 46 </style>
三、總結
1)一般來說,ref
被用來定義簡單的字符串或者數值,而reactive
被用來定義對象數組等
2)實際上都能用,而且ref也可以去定義簡單的對象和數組,也是具有響應式的,不過官方文檔中有提到如果將對象分配為ref值,則可以通過reactive方法使該對象具有高度的響應式。