“This is the fourth day of my participation in the Gwen Challenge.

Above, in Vue3’s Exploration of The Principles of Responsiveness Part 1-20 implementing Responsiveness, we introduced what responsiveness is and a weak version of the implementation. And raises a question, which we address in this article.

Refer to www.vuemastery.com/courses/vue…

How can multiple properties create independent responses

let param = { width: 4.height: 5 };
let size = 0;

let effect = () = > {
    size = param.width * param.height
}
...

Copy the code

We have two attributes of param width | height, they were dependent on other variables, such as:

let param = { width: 4.height: 5 };

let widthNew = param.width * 2;
let sizeNew = Math.PI * param.width * param.width;
let heightNew = param.height * 3;

Copy the code

You can see that width is dependent on widthNew sizeNew and height is dependent on heightNew. When width or height is updated, their corresponding dependencies need to be updated automatically. But how do we do that.

Map is a type introduced in ES6. It is used to store key-value data. You can set a value using a key or get a value. We can consider storing width and height as keys, and storing their corresponding dependencies as values into values.


const depsMap = new Map(a);function track(key) {
    let dep = depsMap.get(key);
    if(! dep) { depsMap.set(key, (dep =new Set));
    }
    dep.add(effect);
}
function trigger(key) {
    let dep = depsMap.get(key);
    if (dep) {
        dep.forEach(effect= >{ effect(); }); }}let param = { width: 5.height: 2 }
let size = 0;
let effect = () = > {
    size = param.width * param.height;
};

track('height');
track('width');
effect();
console.log(size); / / = > 10

param.height = 3;
trigger('height');
console.log(size); / / = > 15


param.width = 6;
console.log(size); // => 15, there is no dependency to trigger 'width' manually, so it is still 15
trigger('width');
console.log(size); / / = > 18
Copy the code

As can be seen from the above implementation, we only need to manually execute the corresponding trigger when the corresponding attribute changes to achieve a simple response.

Multiple responsive objects

If there are multiple different param objects that need to be created reactive, how can the storage structure be adjusted? After all, a real engineering project cannot have only one object.

We could consider another layer of data structure encapsulation, using depsMap as a value for each object implemented above, but the question is what to use as a key.

Fortunately, ES6 provides another structure, WeakMap.

WeakMap can use objects as its own key, and it can only use objects as keys. Backpacks.

let product = { width: 5.height: 2 }
const targetMap = new WeakMap()
targetMap.set(product, "example code to test")
console.log(targetMap.get(product)) // ---> "example code to test"
Copy the code

We named the instance of WeakMap as targetMap, and the adjusted storage structure is shown in the following figure, which can be understood by replacing product Quantity Price total in the figure with Param width height size in our example.

When we create a dependency or trigger, we need to pass in the corresponding object as a parameter so that we know we should respond to that object. The concrete implementation is as follows:

const targetMap = new WeakMap(a);function track(target, key) {
    let depsMap = targetMap.get(target);
    if(! depsMap) { targetMap.set(target, (depsMap =new Map()));
    }
    let dep = depsMap.get(key);
    if(! dep) { depsMap.set(key, (dep =new Set()));
    }
    dep.add(effect);
}
function trigger(target, key) {
    const depsMap = targetMap.get(target);
    if(! depsMap)return;
    let dep = depsMap.get(key);
    if (dep) {
        dep.forEach(element= >{ element(); }); }}let param = { width: 5.height: 2 };
let size = 0;
let effect = () = > {
    size = param.width * param.height;
}
track(param, 'height');
track(param, 'width');
effect();
console.log(size); / / 10;

param.height = 3;
trigger(param, 'height');
console.log(size); / / 15

param.width = 6;
trigger(param, 'width');
console.log(size); / / 18
Copy the code

The above implementation effectively tracks the dependencies of multiple objects, an important starter when creating a responsive system.

A new question

But how do we avoid the weak manual trigger function and trigger automatically? In addition, can we not manually track?

The answer is yes.

We can study first

  • Proxy, a Javascript Proxy Proxy growth journey
  • Reflect, learn about Proxy’s good friend – Reflect

Then, based on Proxy + Reflect, we can use Vue3 to explore the principle of response – Part 3 Proxy + Reflect + activeEffect to achieve automatic response.