Hi FE !
Ai
git
前端面试题
前端小tip
  • vite
  • webpack
npm
  • vue2
  • vue3
react
GitHub
Ai
git
前端面试题
前端小tip
  • vite
  • webpack
npm
  • vue2
  • vue3
react
GitHub
  • reactive对象重新赋值后丢失响应而ref不会

reactive对象重新赋值后丢失响应而ref不会

为什么 ref 调用 reactive 处理对象,为什么重新赋值后,没有失去响应式,但是 reactive 却失去了响应式?

我们去看看源码咋写的:

class RefImpl {
    constructor(value, __v_isShallow) {
        this.__v_isShallow = __v_isShallow;
        this.dep = undefined;
        this.__v_isRef = true;
        this._rawValue = __v_isShallow ? value : toRaw(value);
        this._value = __v_isShallow ? value : toReactive(value);
    }
    get value() {
        trackRefValue(this);
        return this._value; // getter 返回的是_value的值
    }
    set value(newVal) {
        newVal = this.__v_isShallow ? newVal : toRaw(newVal);
        if (hasChanged(newVal, this._rawValue)) {
            this._rawValue = newVal;
            this._value = this.__v_isShallow ? newVal : toReactive(newVal); // setter 调用 toReactive 方法
            triggerRefValue(this, newVal);
        }
    }
}

我们读取 xxx.value 值的时候,getter 返回的是 xxx._value 的值,就是说,ref 定义的数据,value 和 _value 的值是一样的 我们修改 xxx.value 值的时候,setter 调用 toReactive 方法

const toReactive = (value) => isObject(value) ? reactive(value) : value;

toReactive 方法判断是否是对象,是的话就调用 reactive 方法(印证了官网说的,ref 定义对象时,底层调用 reactive 方法实现)
function reactive(target) {
    // if trying to observe a readonly proxy, return the readonly version.
    if (isReadonly(target)) {
        return target;
    }
    return createReactiveObject(target, false, mutableHandlers, mutableCollectionHandlers, reactiveMap);
}

reactive 方法,先判断数据是否是 “只读” 的,不是就返回 createReactiveObject 方法处理后的数据

createReactiveObject 方法将对象通过 proxy 处理为响应式数据

结论

ref 定义数据(包括对象)时,都会变成 RefImpl(Ref 引用对象) 类的实例,无论是修改还是重新赋值都会调用 setter,都会经过 reactive 方法处理为响应式对象。 但是 reactive 定义数据(必须是对象),是直接调用 reactive 方法处理成响应式对象。如果重新赋值,就会丢失原来响应式对象的引用地址,变成一个新的引用地址,这个新的引用地址指向的对象是没有经过 reactive 方法处理的,所以是一个普通对象,而不是响应式对象

解决方法

使用 ref() 定义响应式变量 (推荐此方法,虽然需要多写 .value。但是可以避免很多坑) 在目标对象外边再多定义一个变量 let obj = reactive({ targetObj: {a:1,b:2}}),重新赋值时 obj.targetObj = {c:1,d:2},不会丢失响应式,但是也是要多写一个 obj. 的前缀 (推荐方法一)

Edit this page
最近更新: 2025/6/27 02:24
Contributors: qdleader
qdleader
本站总访问量 129823次 | 本站访客数 12人