Dependency collection & triggering dependencies

Now that we’ve implemented Reactive and effect and left a global variable, activeEffect, let’s think about what these things do and how they fit together.

Analysis of the

Reactive (obj) returns a proxy object. When the program is executed to obj.xx, a get request is triggered and when obJ.xx = xx, a set request is triggered

Effect (fn) returns an instance of ReactiveEffect, which is assigned to the current instance at the time the function is executed. The instance object stores the fn passed in by the user and can be executed via the internal RUN method

thinking

Can we do this through the above preparations? We store effect(FN) when we trigger the get request from obj inside the effect function, and when the program triggers its set request, we pull it out of the stored variables and execute the run function in the instance object one by one, which is equivalent to when the data is updated. Will fn in effect(fn) be executed automatically?

A single measurement

Now let’s improve the single test of Effect, plus the update mechanism

describe("effect".() = > {
  it("happy path".() = >{... user.age++ expect(nextAge).toBe(12)})})Copy the code

When one of the properties of our reactive object changes, we want nextAge to change synchronously.

coding

We implement dependency collection and triggering dependencies step by step

// src/reactivity/reactive.ts
import {track, trigger} from './effect'
export function reactive (raw) {
  return new Proxy(raw, { get (target, key) { ... track(target, key) ... }, set (target, key, value) { ... trigger(target, key) ... }})}Copy the code

The track function above is used to collect dependencies and trigger is used to trigger dependencies, both of which we wrote in the effect.ts file.

Depend on the collection

Simply say depend on collect, but what depend on exactly is, what we want to collect exactly, and how should store, please observe the following picture carefully.

The actual data structure we want to store is target->key->effect.

const targetMap = new Map(a)export function track (target, key) {
  let depsMap = targetMap.get(target)
  if(! depsMap) { depsMap =new Map()
    targetMap.set(target, depsMap)
  }
  let dep = depsMap.get(key)
  if(! dep) { dep =new Set()
    depsMap.set(key, dep)
  }
  dep.add(activeEffect)
}
Copy the code

In the implementation code above, we store all the dependencies we collected with a global variable targetMap in the format of Map, and then read the storage container DEP of target.key from it in turn, and then store activeEffects in it, so we store all fn.

Trigger rely on

Now that we’ve collected all the dependencies above, it’s much easier to trigger them.

export function trigger (target, key) {
  const depsMap = targetMap.get(target)
  const dep = depsMap.get(key)
  dep.forEach((effect) = > {
    effect.run()
  })
}
Copy the code

Depending on the value passed in from trigger(target, key), we extract all of the corresponding Effect instance objects from targetMap, and then execute the run method for each instance, which is our trigger dependency.

The test results

PS D:\user\desktop\mini-vue> yarn testYarn run v1.22.10 $jest PASS/SRC/reactivity tests/effect. The spec. The ts PASS/SRC/reactivity tests/index. The spec. Ts PASS src/reactivity/tests/reactive.spec.ts Test Suites: 3 passed, 3 total Tests: 3 passed, 3 total Snapshots: 0 total Time: 1.108 s Ran alltest suites.
Done in2.36 s.Copy the code

conclusion

Actually vue3 responsive we have basically completed the fundamental function, also can achieve data following changed, didn’t understand always feel very magical, now look at also so return a responsibility, actually coding idea really is too important, even if you understand all the grammar of the API but finally can not write such code, good good study, SAO years!

In the next section, we will refine effect Runner functionality.