• Vue定义响应式数组对象用ref好还是reactive好?
  • 发布于 2个月前
  • 527 热度
    0 评论
用ref包装数组执行过程
// 堆代码 duidaima.com
// 用ref来包装数组 1
const list1 = ref([]);
console.log(list1);
// 创建ref   2
function ref(value) {
    return createRef(value, false);
}

// 创建ref对象,判断传入的值是不是Ref对象,如果是就不需要再次包装了,直接返回
// 3
function createRef(rawValue, shallow) {
    if (isRef(rawValue)) {
        return rawValue;
    }
    return new RefImpl(rawValue, shallow);
}

// 在类的内部可以使用get和set关键字,对某个属性这种存储值函数和取值函数,
// 拦截该属性的存取行为(此时就可以做想做的事情,如,set中,就可以去修改
// 视图中对用参数的数据)
// 这也是响应式的基本原理,
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);
        // 4 实例化一个对象时,对对象的_value值进行赋值
        this._value = __v_isShallow ? value : toReactive(value);
    }
    get value() {
        trackRefValue(this);
        return this._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);
            triggerRefValue(this, newVal);
        }
    }
}

// 此时去判断传入的数据的类型   5
// 如果是基本数据类型,那么直接返回当前值
// 如果是对象类型,则通过reactive函数对其操作
const toReactive = (value) => isObject(value) ? reactive(value) : value;

// 创建 createReactiveObject 对象
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包装数组执行过程
const list = reactive([]);
console.log(list);
// 堆代码 duidaima.com
// 判断是否只读
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);
}

// 创建 createReactiveObject 对象
function createReactiveObject(target, isReadonly, baseHandlers, collectionHandlers, proxyMap) {
    if (!isObject(target)) {
        if ((process.env.NODE_ENV !== 'production')) {
            console.warn(`value cannot be made reactive: ${String(target)}`);
        }
        return target;
    }
    // target is already a Proxy, return it.
    // exception: calling readonly() on a reactive object
    if (target["__v_raw" /* RAW */] &&
        !(isReadonly && target["__v_isReactive" /* IS_REACTIVE */])) {
        return target;
    }
    // target already has corresponding Proxy
    const existingProxy = proxyMap.get(target);
    if (existingProxy) {
        return existingProxy;
    }
    // only specific value types can be observed.
    const targetType = getTargetType(target);
    if (targetType === 0 /* INVALID */) {
        return target;
    }
    // 通过Proxy类对target对象生成一个代理对象
    const proxy = new Proxy(target, targetType === 2 /* COLLECTION */ ? collectionHandlers : baseHandlers);
    proxyMap.set(target, proxy);
    return proxy;
}
通过对源码的阅读,我们可以看到,通过ref方法包装获取一个响应式的对象list1,返回的是一个RefImpl类型的对象,该对象的value值的是 Proxy类型的实例化对象。通过reactive方法包装获取一个响应式对象list,返回的是一个Proxy类型的实例化对象

这两种方法都可以定义响应式数组对象,且两者的定义本质上还是 一个Proxy类型的实例化对象,但用ref包装的数组生成的响应式对象多了一层,即RefImpl类型的对象。所以定义响应式数组对象,用reactive比较合适。
用户评论