ref/reactive 都能创建一个响应对象,这二者的区别是什么呢?
一、reactive
reactive 都能创建一个响应对象或数组
1、reactive 用来创建引用类型的响应式数据
2、reactive 的本质是将每一层的数据都解析成 proxy 对象
3、reactive 的响应式默认都是递归的,改变某一层的值都会递归的调用一遍,重新渲染 dom
4、直接解构,响应性会丢失,需要用 toRefs 包裹。引用类型直接改变引用地址也会导致响应式丢失
1 2 3
| <tempalte> <div>{{ state.count }}</div> </tempalte>
|
1 2 3 4 5
| <script setup> import { reactive } from "vue" const state = reactive({count:0}) </script>
|
二、ref
vue3 提供了一个 ref()方法允许我们创建使用任何值类型的响应式 ref
1、ref 用来创建基础类型的响应式数据
2、template 中默认调用 value 显示数据,script 中需要使用.value 调用
3、和 react ref 差不多,react 是.current 获取值,vue3 是.value
1 2 3 4 5
| import { ref } from "vue"; const count = ref(0); console.log(count); count.value++; console.log(count.value);
|
相关 API
1、Ref ts 定义 import { type Ref } from ‘vue’;
2、isRef 判断是否为 ref 对象。一般是 ref,toRef,toRefs 创建的变量
3、toRefs 将 reactive 对象解构为单个响应式对象
4、shallowRef 创建一个跟踪自身 .value 变化的 ref,但不会使其值也变成响应式的,简单理解为创建一个和 ref 相同结构的非响应式变量
5、triggerRef 强制更新页面 DOM。即使创建的 ref 没有变,想更新 dom 可以用
6、customRef 提供类似于 computed 的 get 和 set,可自定义 ref 行为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| <template> <HelloWorld msg="Hello Vue 3.0 + Vite" @some-event="callback" /> <div>父组件监听事件:{{ counts }}</div> <p>v-model</p> <custom-input :modelValue="searchText" @update:modelValue="newValue => searchText = newValue" /> <Child /> <h2> reactive方法用来创建响应式对象,它接收一个对象/数组参数,返回对象的响应式副本,当该对象的属性值发生变化,会自动更新使用该对象的地方。 </h2> <div> Object:{{ reactiveObj.name }} <span @click="setReactiveObj">Update</span> </div> <div> Array:{{ reactiveArr }} <span @click="setReactiveArr">Update</span> </div> <h2> ref 的作用就是将一个原始数据类型(primitive data type)转换成一个带有响应式特性的数据类型,原始数据类型共有7个,分别是:String/ Number /BigInt /Boolean /Symbol /Null /Undefined。 ref的值在 JS/TS 中读取和修改时,需要使用 .value获取,在模版中读取是,不需要使用 .value。 </h2> <div> String:{{refValue}} <button @click="setRefValue">Update</button> </div> <div> Object:{{ refObj.name }} <button @click="setRefObj">Update</button> </div> <h2>vue3 reactive deep Obj/array</h2> <div> Deep Object:{{ reactiveDeepObj }} <button @click="setReactiveDeepObj">Update</button> </div> <div> Deep Object Array: {{ reactiveDeepArr }} <button @click="setReactiveDeepArr">update</button> </div> </template>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| <script setup> import HelloWorld from './components/HelloWorld.vue' import CustomInput from "./components/CustomInput.vue" import Child from "./components/Child.vue"
import { ref, reactive, nextTick, provide } from "vue" let counts = ref(10)
const callback = () => { nextTick(() => { counts.value = 14 }) }
const provideMsg = ref("provide message") provide("provideMsg", provideMsg)
let reactiveObj = reactive({ name: 'jude' })
let setReactiveObj = () => { reactiveObj.name = 'hello,jude' }
let reactiveArr = reactive(['a', 'b', 'c', 'd']) let setReactiveArr = () => { reactiveArr[1] = 'hello,jude!' }
let refValue = ref('jude 1992') let setRefValue = () => { refValue.value = 'hello jude 1992' }
let refObj = ref({ name: 'jude 1992' }) let setRefObj = () => { refObj.value.name = 'hello jude 1992' }
let reactiveDeepObj = reactive( { user: { name: 'jude 1992' } } ) let setReactiveDeepObj = () => { reactiveDeepObj.user.name = 'hello jude 1992' }
let reactiveDeepArr = reactive( ['a', ['a1', 'a2', 'a3'], 'c', 'd'] ) let setReactiveDeepArr = () => { reactiveDeepArr[1][1] = "hello jude 1992" }
let reactivSource = { name: 'jude 1992' } let reactiveData = reactive(reactivSource) console.log(reactivSource === reactiveData) console.log('reactivSource', reactivSource); console.log('reactiveData', reactiveData);
</script>
|
三、总结
1.reactive 一般用于对象/数组类型的数据,都不需要使用 .value;
2.ref 一般用于基础数据类型的数据,在 JS 中读取和修改时,需要使用 .value,在模版中使用时则不需要;
3.reactive 可以修改深层属性值,并保持响应;
4.reactive 返回值和源对象不同;
5.reactive 的属性值可以是 ref 值;
6.ref 本质也是 reactive,ref(obj)等价于 reactive({value: obj})。
ref 接收内部值(inner value)返回响应式 Ref 对象,reactive 返回响应式代理对象;从定义上看 ref 通常用于处理单值的响应式,reactive 用于处理对象类型的数据响应式;两者均是用于构造响应式数据,但是 ref 主要解决原始值的响应式问题;ref 返回的响应式数据在 JS 中使用需要加上.value 才能访问其值,在视图中使用会自动脱 ref,不需要.value;ref 可以接收对象或数组等非原始值,但内部依然是 reactive 实现响应式;reactive 内部如果接收 Ref 对象会自动脱 ref;使用展开运算符(…)展开 reactive 返回的响应式对象会使其失去响应性,可以结合 toRefs()将值转换为 Ref 对象之后再展开;reactive 内部使用 Proxy 代理传入对象并拦截该对象各种操作(trap),从而实现响应式。ref 内部封装一个 RefImpl 类,并设置 get value/set value,拦截用户对值的访问,从而实现响应式。