Introduce a,

Looking at the ref source code before, I found that it relies on track for collection and updates notification through trigger. Both functions are defined in the effect.ts file.

Second, source code analysis

2.1: track

// packages\reactivity\src\effect.ts

// Currently active side effects, similar to Watcher in VUe2
let activeEffect: ReactiveEffect | undefined

// Used to store the original object and activeEffect dependencies
// Is a 2-dimensional map
// Map of the first layer: key is the original object, value is a map
// Map: key is the attribute name of the original object, and value is the dependency set of the attribute
const targetMap = new WeakMap<any, KeyToDepMap>()

// The first argument: the original object
// The second argument: type
// The third argument: the attribute name of the original object, namely key
export function track(target: object.type: TrackOpTypes, key: unknown) {
  // Determine whether track should be performed
  if(! shouldTrack || activeEffect ===undefined) {
    return
  }
  
  // There are no dependencies in the current targetMap to store the original object
  let depsMap = targetMap.get(target)
  if(! depsMap) {// If there is no storage, the original object is used as the key, and the value is a newly created empty map
    targetMap.set(target, (depsMap = new Map()))}// There is no dependency set for key
  let dep = depsMap.get(key)
  if(! dep) {// If there is no dependency set, create an empty set to store the dependency
    depsMap.set(key, (dep = new Set()))}// Determine if there are currently activeeffects in the dependency set that should be collected
  if(! dep.has(activeEffect)) {Activeeffects should be collected if they are not already collected
    dep.add(activeEffect)
    ActiveEffect dependencies are also collected synchronously, which means that both sides collect each other
    activeEffect.deps.push(dep)
  }
}
Copy the code

Conclusion: The track method mainly maintains targetMap, which maintains the ActiveEffects that should be collected by the attributes of the original object.

2.2 the trigger

export function trigger(
  target: object.type: TriggerOpTypes, key? : unknown, newValue? : unknown, oldValue? : unknown, oldTarget? :Map<unknown, unknown> | Set<unknown>
) {
  const depsMap = targetMap.get(target)
  // This property has never been tracked and does not need to trigger the update notification
  if(! depsMap) {// never been tracked
    return
  }
  
  // Define a set to store the activeEffects to be notified
  const effects = new Set<ReactiveEffect>()
  // Define the add method
  const add = (effectsToAdd: Set<ReactiveEffect> | undefined) = > {
    if (effectsToAdd) {
      effectsToAdd.forEach(effect= > {
        if(effect ! == activeEffect || effect.allowRecurse) { effects.add(effect) } }) } }// A change of type clear notifies all dependencies
  if (type === TriggerOpTypes.CLEAR) {
    // collection being cleared
    // trigger all effects for target
    depsMap.forEach(add)
  } else if (key === 'length' && isArray(target)) {
    // A change in the array length type notifies the dependency corresponding to the key that exceeds the new length
    depsMap.forEach((dep, key) = > {
      if (key === 'length' || key >= (newValue as number)) {
        add(dep)
      }
    })
  } else {
    // schedule runs for SET | ADD | DELETE
    if(key ! = =void 0) {
      add(depsMap.get(key))
    }
  }
  
  // Define the run method to perform the effect update
  const run = (effect: ReactiveEffect) = > {
    if(effect.options. Scheduler executes) {// Execute via scheduler
      effect.options.scheduler(effect)
    } else {
      // Execute directly
      effect()
    }
  }
  
  // Execute the run method on all dependencies that should be notified
  effects.forEach(run)
}
Copy the code

Summary: The trigger method determines which key dependencies should be updated based on type and performs the update of the dependencies.