解析vue3响应式原理以及api编写

前言

vue3响应式原理加api编写,快速明白vue3响应式原理

GitHub博客:https://github.com/jiejiangzi/blog/issues/8

vue3响应式原理实现

先写一段代码看下

实现effect

  1. var name = 'sl', age = 22;effect1 = () => `我叫${name},今年${age}岁`effect2 = () => `我叫${name},今年${age+1}岁`console.log(effect1()) //我叫sl,今年22岁console.log(effect2()) //我叫sl,今年23岁age = 30;console.log(effect1())  //我叫sl,今年30岁console.log(effect2())  //我叫sl,今年31岁

登录后复制

看看有什么可以优化的点呢?

立即学习“前端免费学习笔记(深入)”;

首先:多个函数,在age发生变化后需要手动再次调用多个函数才可以获取最新信息

期望可以修改信息以后自动调用多个函数

如何实现呢

可以想到将多个函数存放到一起存放到gather函数,并且让age发生变化时可以将多个函数调用trigger调用

实现gather及trigger

  1. var name = "sl",  age = 22;var tom, joy;effect1 = () => (tom = `我叫${name},今年${age}岁`);effect2 = () => (joy = `我叫${name},今年${age + 1}岁`);var dep = new Set();function gather() {  dep.add(effect1);  dep.add(effect2);}function trigger() {  dep.forEach((effect) => effect());}gather();effect1()effect2()console.log(tom); //我叫sl,今年22岁console.log(joy); //我叫sl,今年23岁age = 30;trigger()console.log(tom); //我叫sl,今年30岁console.log(joy); //我叫sl,今年31岁

登录后复制

再继续看下还是有什么可以优化的点

如果变量是一个对象或多个对象的话该怎么处理呢

变量为原始类型时Set存储

变量为对象时可以用map存储

多个对象时用weakMap存储

  1. var obj1 = { name: "tom", age: 22 };var obj2 = { name: "joy", age: 23 };var tom, joy;effect1 = () => (tom = `我叫${obj1.name},今年${obj1.age}岁`);effect2 = () => (joy = `我叫${obj2.name},今年${obj2.age}岁`);var depsMap = new WeakMap();function gather(target, key) {  let depMap = depsMap.get(target);  if (!depMap) {    depsMap.set(target, (depMap = new Map()));  }  let dep = depMap.get(key);  if (!dep) {    depMap.set(key, (dep = new Set()));  }  if (target === obj1) {    dep.add(effect1);  } else {    dep.add(effect2);  }}function trigger(target, key) {  let depMap = depsMap.get(target);  if (depMap) {    const dep = depMap.get(key);    if (dep) {      dep.forEach((effect) => effect());    }  }}gather(obj1, "age");//收集依赖gather(obj2, "age");//收集依赖effect1();effect2();console.log(tom); //我叫sl,今年22岁console.log(joy); //我叫sl,今年23岁obj1.age = 30;obj2.age = 10;trigger(obj1, "age");trigger(obj2, "age");console.log(tom); //我叫sl,今年30岁console.log(joy); //我叫sl,今年31岁

登录后复制

在继续看看有哪些可以优化的点

上边依赖的收集gather以及函数的更新通知trigger每次都是手动收集手动触发更新,那有什么方法可以自动收集及触发吗

Proxy

实现reactive

先写一个reactive函数

  1. function reactive(target) {  const handle = {    set(target, key, value, receiver) {      Reflect.set(target, key, value, receiver);      trigger(receiver,key) // 设置值时触发自动更新    },    get(target, key, receiver) {      gather(receiver, key); // 访问时收集依赖      return Reflect.get(target, key, receiver);    },  };  return new Proxy(target, handle);}

登录后复制

然后将reactive函数应用到之前代码

  1. var obj1 = reactive({ name: "tom", age: 22 });var obj2 = reactive({ name: "joy", age: 23 });var tom, joy;effect1 = () => (tom = `我叫${obj1.name},今年${obj1.age}岁`);effect2 = () => (joy = `我叫${obj2.name},今年${obj2.age}岁`);var depsMap = new WeakMap();function gather(target, key) {  let depMap = depsMap.get(target);  if (!depMap) {    depsMap.set(target, (depMap = new Map()));  }  let dep = depMap.get(key);  if (!dep) {    depMap.set(key, (dep = new Set()));  }  if (target === obj1) {    dep.add(effect1);  } else {    dep.add(effect2);  }}function trigger(target, key) {  let depMap = depsMap.get(target);  if (depMap) {    const dep = depMap.get(key);    if (dep) {      dep.forEach((effect) => effect());    }  }}effect1();effect2();console.log(tom); //我叫sl,今年22岁console.log(joy); //我叫sl,今年23岁obj1.age = 30;obj2.age = 10;console.log(tom); //我叫sl,今年30岁console.log(joy); //我叫sl,今年31岁

登录后复制

然后还有个问题,就是gather函数中有写死dep添加函数

如何解决呢 重写effect函数

  1. let activeEffect = nullfunction effect(fn) {  activeEffect = fn;  activeEffect();  activeEffect = null; // 执行后立马变成null}var depsMap = new WeakMap();function gather(target, key) {  // 避免例如console.log(obj1.name)而触发gather  if (!activeEffect) return;  let depMap = depsMap.get(target);  if (!depMap) {    depsMap.set(target, (depMap = new Map()));  }  let dep = depMap.get(key);  if (!dep) {    depMap.set(key, (dep = new Set()));  }  dep.add(activeEffect) //将函数添加到依赖}effect(effect1);effect(effect2);

登录后复制

reactive也已经实现了,那么还有ref也实现下

ref

在vue3中ref怎么使用呢

  1. var name = ref('tom')console.log(name.value) // tom

登录后复制

需要使用.value的方式获取值

  1. function ref(name){    return reactive(        {            value: name        }    )}const name = ref('tom');console.log(name.value) //tom

登录后复制

完整代码

  1. var activeEffect = null;function effect(fn) {  activeEffect = fn;  activeEffect();  activeEffect = null; }var depsMap = new WeakMap();function gather(target, key) {  // 避免例如console.log(obj1.name)而触发gather  if (!activeEffect) return;  let depMap = depsMap.get(target);  if (!depMap) {    depsMap.set(target, (depMap = new Map()));  }  let dep = depMap.get(key);  if (!dep) {    depMap.set(key, (dep = new Set()));  }  dep.add(activeEffect)}function trigger(target, key) {  let depMap = depsMap.get(target);  if (depMap) {    const dep = depMap.get(key);    if (dep) {      dep.forEach((effect) => effect());    }  }}function reactive(target) {  const handle = {    set(target, key, value, receiver) {      Reflect.set(target, key, value, receiver);      trigger(receiver, key); // 设置值时触发自动更新    },    get(target, key, receiver) {      gather(receiver, key); // 访问时收集依赖      return Reflect.get(target, key, receiver);    },  };  return new Proxy(target, handle);}function ref(name){    return reactive(        {            value: name        }    )}

登录后复制

推荐学习:《最新的5个vue.js视频教程精选》

以上就是解析vue3响应式原理以及api编写的详细内容,更多请关注【创想鸟】其它相关文章!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

点点赞赏,手留余香

给TA打赏
共0人
还没有人赞赏,快来当第一个赞赏的人吧!
    编程技术

    介绍Vue3中Composition API及其核心用法

    2025-4-1 17:23:47

    编程技术

    认识Vue中的computed 和 watch,聊聊它们的区别

    2025-4-1 17:24:01

    0 条回复 A文章作者 M管理员
    欢迎您,新朋友,感谢参与互动!
      暂无讨论,说说你的看法吧
    个人中心
    购物车
    优惠劵
    今日签到
    私信列表
    搜索