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  没写setup需要在setup(){}内部定义 并返回(return)
<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); // { value:0 }
count.value++;
console.log(count.value); // 2

相关 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)


// reactive
let reactiveObj = reactive({ name: 'jude' })

let setReactiveObj = () => {
reactiveObj.name = 'hello,jude'
}

let reactiveArr = reactive(['a', 'b', 'c', 'd'])
let setReactiveArr = () => {
reactiveArr[1] = 'hello,jude!'
}

// Ref
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'
}

// reactive可以用在深层对象或者数组
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"
}

// reactive 返回值和源对象不相等
let reactivSource = { name: 'jude 1992' }
let reactiveData = reactive(reactivSource)
console.log(reactivSource === reactiveData) // false
console.log('reactivSource', reactivSource);
console.log('reactiveData', reactiveData);


// ts写法
// let refObjValue = ref < string > ('jude 1992')
// let reactiveObjValue = reactive < { name: string } > ({ name: 'jude 1992' })
</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,拦截用户对值的访问,从而实现响应式。