【vue3】Composition api by hand

Introduction

This article mainly emphasizes on rewriting composition api by hand. Four sets of api are included in the article, which are shallowReactive and reactive, shallowRef and ref, shallowReadonly and readonly and isRef, isReactive, isReadonly and isProxy respectively. The main implementation of the api is data hijacking operation, while the update operation has not yet been involved.

shallowReactive & reactive

//shallowReactive and reactive
//Define reactiveHandler
const reactiveHandler = {
    //Get property
    get(target, property) {
        if (property === '_is_reactive') return true;
        const result = Reflect.get(target, property);
        console.log('Intercept get operation', property, result);
        return result;
    },
    //Amend or add property
    set(target, property, val) {
        const result = Reflect.set(target, property);
        console.log('Intercept amend operation or add operation', property, val);
        return result;
    },
    //Delete property
    deleteProperty(target, property) {
        const result = Reflect.deleteProperty(target, property);
        console.log('Intercept delete operation', property);
        return result;
    }

}


//Define shallowReactive function
//Parameter is a target object
function shallowReactive(target) {
    //Determines if the target object is of type Object (object/array)
    if (target && typeof target === 'object') {
        return new Proxy(target, reactiveHandler);
    }
    //If the target is of primitive type, return target directly
    return target;
}

//Define reactive function
function reactive(target) {
    //Determines if the target object is of type Object (object/array)
    if (target && typeof target === 'object') {
        //Processes all the data in an array or object recursively via reactive
        //Determine if current target is of type array
        if (Array.isArray(target)) {
            //Data traversal in array
            target.forEach((item, index) => {
                target[index] = reactive(item);
            })
        } else {
            //Determine if current target is of type object
            //Data traversal in object
            Object.keys(target).forEach(key => {
                target[key] = reactive(target[key]);
            })
        }
        return new Proxy(target, reactiveHandler);
    }
    //If the target is of primitive type, return target directly
    return target;
}

shallowReadonly and readonly

//shallowReadonly and readonly
//Define readonlyHandler
const readonlyHandler = {
    get(target, property) {
        if (property === '_is_readonly') return true;
        const result = Reflect.get(target, property);
        console.log('Intercept get operation', property, result);
        return result;
    },

    set(target, property, val) {
        console.warn('Read only, cannot amend data or add data');
        return true;
    },

    deleteProperty(target, property) {
        console.warn('Read only, cannot delete data');
        return true;
    },
}

//Define shallowReadonly function
function shallowReadonly(target) {
    //Determine if current target is of type object
    if (target && typeof (target) === 'object') {
        return new Proxy(target, readonlyHandler);
    }
    return target;
}

//Define readonly function
function readonly(target) {
    //Determine if current target is of type object
    if (target && typeof (target) === 'object') {
        //Determine if current target is of type array
        if (Array.isArray(target)) {
            target.forEach((item, index) => {
                target[index] = readonly(item);
            })
        } else {
            //Current target is of type object
            Object.keys(target).forEach(key => {
                target[key] = readonly(target[key]);
            })
        }
        return new Proxy(target, readonlyHandler);
    }
    //If target is of type primary data, return target directly
    return target;
}

shallowRef and ref

//shallowRef and ref
//Define shallowRef function
function shallowRef(target) {
    //Save target
    return {
        _value: target,
        get value() {
            console.log('Intercept read operation')
            return this._value;
        },
        set value(value) {
            console.log('Intercept set operation and ready to update', value)
            this._value = value;
        }
    }
}

//Define ref function
function ref(target) {
    target = reactive(target);
    return {
        //Curent object is of type ref
        _is_ref: true,
        _value: target,
        get value() {
            console.log('Intercept read operation')
            return this._value;
        },
        set value(value) {
            console.log('Intercept set operation and ready to update', value)
            this._value = value;
        }
    }
}

isRef, isReactive, isReadonly and isProxy

//isRef, isReactive, isReadonly and isProxy
//Define isRef function to determine if current object is of type ref
function isRef(object) {
    return object && object._is_ref
}
//Define isReactive function to determine if current object is of type reactive
function isReactive(object) {
    return object && object._is_reactive
}
//Define isReadonly function to determine if current object is of type readonly
function isReadonly(object) {
    return object && object._is_readonly
}
//Define isProxy function to determine if current object is of type reactive or readonly
function isProxy(object) {
    return isReactive(object) || isReadonly(object)
}

Test Results

shallowReactive

const proxy1 = shallowReactive({
        name: "James",
        car: {
          color: "red ",
        },
      });
      //Get data and set data successfully
      proxy1.name += "=====";
      //Get data successfully, but fail to set data
      proxy1.car.color += "++++++";
      //Delete data successfully
      delete proxy1.name;
      //Get data successfully, but fail to delete it
      delete proxy1.car.color;

在这里插入图片描述

reactive

 const proxy2 = reactive({
        name: "James",
        car: {
          color: "red ",
        },
      });
      //The reactive conversion is "deep": it affects all nested properties.
      proxy2.name += "=====";
      proxy2.car.color += "++++++";
      delete proxy2.name;
      delete proxy2.car.color;

在这里插入图片描述

shallowReadonly

      const proxy3 = shallowReadonly({
        name: "James",
        car: {
          color: ["red", "blue"],
        },
      });
      // Read operation is valid
      console.log(proxy3.name);
      // Cannot change the value of name property
      proxy3.name = "==";
      // Delete is not valid
      delete proxy3.name;
      // Deep amend or delete is valid
      proxy3.car.color[0] = "yellow";
      delete proxy3.car.color[1];

在这里插入图片描述

readonly

      const proxy4 = readonly({
        name: "James",
        car: {
          color: ["red", "blue"],
        },
      });
      //Read operation is valid
      console.log(proxy4.name);
      console.log(proxy4.car.color[0]);
      // Change the value of property is not valid
      proxy4.name = "Jack";
      proxy4.car.color[0] = "grey";

在这里插入图片描述

shallowRef

      const ref1 = shallowRef({
        name: "James",
        car: {
          color: ["red", "blue"],
        },
      });
      //Read operation is valid
      console.log(ref1.value);
      //Shallow amend is valid, while deep amend is not valid
      ref1.value = "==";
      ref1.value.car = "==";

在这里插入图片描述

ref

      const ref2 = ref({
        name: "James",
        car: {
          color: ["red", "blue"],
        },
      });
      //Read operation is valid
      console.log(ref2.value);
      //Both shallow and deep amend are hijacked
      ref2.value = "==";
      //ref2.value.car.color[0] = "==";

在这里插入图片描述

ref2.value.car.color[0] = "==";

在这里插入图片描述

isRef, isReactive, isReadonly and isProxy

      console.log(isRef(ref({})));
      console.log(isReactive(reactive({})));
      console.log(isReadonly(readonly({})));
      console.log(isProxy(reactive({})));
      console.log(isProxy(readonly({})));

在这里插入图片描述

Conclusion

About ref

  1. Takes an internal value and returns a reactive, mutable ref object with a single property, .value, which points to its internal value.
  2. ref objects are mutable, which means you can assign new values to.value. It is also reactive in the sense that all operations on.value are tracked and writing operations trigger side effects associated with them.
  3. If an object is assigned to ref, the object is turned into a deeply reactive object via reactive(). This also means that if the object contains nested refs, they will be deeply unpacked.

About reactive

  1. A reactive transformation is “deep” : it affects all nested properties. A reactive object will also deeply unpack any ref attributes while remaining reactive.
  2. It’s worth noting that ref unpacking is not performed when a ref element in a reactive array or a native collection type like Map is accessed.
  3. The returned object, and any objects nested within it, are wrapped in ES Proxy and are therefore not equal to the source object, so it is recommended to use only reactive proxies instead of raw objects.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

葫芦侠不是葫芦娃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值