Home > Web Front-end > Vue.js > body text

Analysis of vue3 responsiveness principle and api writing

藏色散人
Release: 2021-12-10 14:57:47
forward
1486 people have browsed it

Preface

vue3 responsive principle plus api writing, quickly understand the vue3 responsive principle

GitHub Blog: https://github .com/jiejiangzi/blog/issues/8

vue3 responsive principle implementation

Write a piece of code first and take a look

Implement effect

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岁
Copy after login

Let’s see what can be optimized?

First of all: multiple functions. After the age changes, multiple functions need to be manually called again to obtain the latest information.

It is expected that multiple functions can be automatically called after the information is modified.

How to implement it

You can think of storing multiple functions together in the gather function, and when the age changes, multiple functions can be called trigger calls

Implement gather and trigger

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岁
Copy after login

Let’s continue and see if there are any points that can be optimized

What to do if the variable is one object or multiple objects

  • Set storage when the variable is a primitive type

  • When the variable is an object, you can use map to store it

  • When you have multiple objects, you can use weakMap to store it

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岁
Copy after login

Let’s continue to see what points can be optimized

The collection gather and function update notification trigger relied on above are manually collected and triggered to update each time. Is there any way to automatically collect and trigger

Proxy

Implement reactive

Write a reactive function first

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);
}
Copy after login

Then apply the reactive function to the previous code

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岁
Copy after login

Then there is another problem, that is, there is a hard-coded dep addition function in the gather function

How to solve it? Rewrite the effect function

let activeEffect = null
function 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);
Copy after login

reactive has also been implemented, then ref has also been implemented

ref

How to use ref in vue3

var name = ref('tom')
console.log(name.value) // tom
Copy after login

You need to use .value to get the value

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

Complete code

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
        }
    )
}
Copy after login

Recommended study: "Latest 5 vue.js video tutorial selection

The above is the detailed content of Analysis of vue3 responsiveness principle and api writing. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:juejin.im
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template