vue3中ref和reactive的区别
vue3中ref和reactive的区别
·
最近在学vue3,把学习过程进行一个记录。
关于最基本的ref和reactive,网上的文章很多,这里自己做一个总结。
使用区别
二者都是用于定义响应式数据,表面上的区别比较简单:
- reactive定义引用数据类型,ref 定义基本类型
- reactive定义的变量直接使用,ref 定义的变量使用时需要.value
- 模板中均可直接使用,vue帮我们判断了是reactive还是ref定义的(通过__v_isRef属性),从而自动添加了.value。
例如:
// 定义
let count = ref(0);
let obj = reactive({a: 1, b: 2});
// 使用
count.value = 1;
menu = {a: 1, b: 2, c: 3};
return {
count,
...toRefs(menu)
}
本质区别
源码细节较多,本篇只分析关于ref和reactive的核心代码
首先找到ref函数,调用了createRef函数,而createRef返回了RefImpl类
...
export function ref(value?: unknown) {
return createRef(value, false) // 创建ref
}
function createRef(rawValue: unknown, shallow: boolean) {
if (isRef(rawValue)) {
return rawValue
}
return new RefImpl(rawValue, shallow) // 返回一个RefImpl对象
}
再来看下RefImpl类,是不是似曾相识的感觉,没错就是Object.defineProperty,这里做的事情就是收集依赖,触发依赖,只是换了个写法而已。
class RefImpl<T> {
private _value: T // 用来保存加工后实现响应化的值
private _rawValue: T // 用来保存当前未经加工过的值
public dep?: Dep = undefined // 用来收集依赖,这是一个 Set类型
public readonly __v_isRef = true // 用来标识该值是否经过 ref 加工
constructor(value: T, public readonly __v_isShallow: boolean) {
// __v_isShallow 默认没有传,故默认为undefined,这里分别调用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函数,可以看到,如果传入的参数是一个对象的话,返回值将会调用 reactive 方法来进行包裹,reactive 最终会通过 Proxy 来实现响应式
export const toReactive = <T extends unknown>(value: T): T =>
isObject(value) ? reactive(value) : value
结论
- ref创建基本数据类型时,是通过vue2中类似与Object.defineProperty的做法实现响应
- ref创建对象时,内部调用的是reactive
也就是说,vue3中ref实际的对reactive的二次封装增强,reactive能做的ref一定能做。所以个人在开发中习惯性都写ref了。
更多推荐
已为社区贡献3条内容
所有评论(0)