Vue 3 中 ref 和 reactive 的区别及原理
在 Vue 3 中,ref 和 reactive 是创建响应式数据的两种常用方式。很多开发者在使用过程中会对它们的区别和原理产生疑问,尤其是为什么 ref 需要用 .value 取值。今天我们就来深入探讨一下这个问题。
一、reactive 的原理和局限性
reactive 是 Vue 3 中用于创建响应式对象的函数,它的参数必须是一个对象,返回值是一个 Proxy 对象,具有响应性。例如:
import { reactive } from 'vue'
const state = reactive({ count: 0 })
console.log(state.count) // 0
然而,reactive 有一些局限性。首先,它的参数只支持对象类型,不支持基本数据类型。其次,如果对变量重新赋值,会丢失响应性。例如:
let state = reactive({ count: 0 })
state = reactive({ count: 1 }) // 响应性丢失
此外,解构赋值也容易丢失响应性:
const state = reactive({ count: 0 })
let { count } = state
count++ // 不会影响 original state
在这种情况下,我们可以使用 toRefs 函数将响应式对象转换为 ref 对象,以保持响应性。
二、ref 的优势和原理
ref 是另一种创建响应式数据的方式,它的参数既可以是基本数据类型的值,也可以是对象。例如:
import { ref } from 'vue'
const name = ref('张三')
console.log(name.value) // 张三
ref 的优势在于它支持基本数据类型,并且在取值时需要加上 .value。这使得 ref 在开发中更灵活,也更推荐使用。
从源码角度看,ref 的实现是通过 RefImpl 类,其中定义了 get 和 set 函数。当我们对 ref 的值进行取值和赋值时,会触发这两个函数。例如:
class RefImpl {
get value () {
console.log('get')
return '111'
}
set value (val) {
console.log('set')
}
}
const ref = new RefImpl()
ref.value = '123'
ref.value
这里,ref.value 的取值和赋值会分别触发 get 和 set 函数。这就是为什么 ref 需要用 .value 取值的原因。
三、ref 和 reactive 的关系
虽然 ref 和 reactive 都是用于创建响应式数据,但它们的实现方式有所不同。ref 的底层也用到了 reactive,只不过 ref 多包装了一层,支持了基本数据类型的值。例如:
this._value = __v_isShallow ? value : toReactive(value)
这里的 toReactive 函数会将对象类型的值转换为响应式对象,而 ref 则在此基础上支持了基本数据类型。
四、总结
在 Vue 3 中,ref 和 reactive 都是重要的响应式工具。ref 更加灵活,支持基本数据类型,而 reactive 则适用于对象类型的响应式数据。在开发中,我们更推荐使用 ref,因为它能更好地满足各种需求。
希望这篇文章能帮助你更好地理解 Vue 3 中 ref 和 reactive 的区别和原理。