We’ve already made data reactive, but how do we make user-defined methods available when the data changes? New Watcher will pass in a callback as a parameter. This callback can be a user-defined method. The callback will be called when the data in the Watcher response changes. So why does Watcher call callback when its data changes? This involves collecting dependencies. First of all, the data is already observe-that is, it’s already responsive. In the constructor of the Watcher, it gets the value of the data to subscribe to, and that fires the getter for the data, and when it fires the getter collects the Watcher instance into an array subs, and when the data is changed, it fires the setter, Then in the setter it loops through the subs array, notifying one by one, executing the update method, and finally firing the callback from the update method. What is dependency?
Where data is needed is called a dependency. In Ve2. X, the component that uses data is a dependency. Notify the component when data changes, perform diff algorithms within the component via the virtual DOM to collect dependencies in the getter and fire dependencies in the setter
The Dep class is used to encapsulate the code that depends on the collection, // dep.js export default class Dep {constructor(arg) {// This. Subs = []}
// Add a subscription addSub(sub) {this.subs.push(sub)}
If (dep.target) {this.addSub(dep.target)}} if (dep.target) {this.addSub(dep.target)}}
// Notify notify() {const subs = this.subs.slice() // Shallow clone subs.foreach (item => {item.update()})}} copy code to each Observer Const Dep = new Dep() // observer.js… Import Dep from ‘./ dep.js’ export default class Observer {constructor(value) {this.dep = new Dep() I don’t have to write it here… }… } There is also a place to create a Dep instance, The purpose of defineReactive is to send notification dep.notify() // definereactive.js import dep from ‘./ dep.js’ export when the detected object setters default function defineReactive(data, key, value) { const dep = new Dep() … Object.defineProperty(data, key, { … set(newValue) { … // Trigger dependency dep.notify()}})} Copy code deP uses publishing-subscribe mode to loop through the dependency list when data changes, notifies all Watcher. In this way, whenever you modify obj, such as obj.b = 3, the notify method of Dep is executed. Ob.dep.notify () // array.js/ob.dep.notify() // array.js/ob.dep.notify() // array.js… methodsCouldChange.forEach(item => { … def(arrayMethods, item, function() { … ob.dep.notify() … }, false) }) … Our final goal is to create a new instance of the Watcher class in index.js to monitor the specified properties of our specified object, and hope that in the third argument of new Watcher(), The lobyte callback gets the value of the object before and after the modification, so we can do whatever we want. // index.js import observe from ‘./observe.js’ import Watcher from ‘./Watcher.js’
let obj = { a: { m: { n: 1 } } } observe(obj) new Watcher(obj, ‘a.m.n’, (val, oldValue) => { console.log(‘watcher’, val, OldValue)}) obj.a.m.n = 2 The expected result of copying the code is
That is, as long as I create a new Watcher instance and pass in the properties I want to monitor (A.M.N) and object (obj), I can get the old and new properties of obj.a.m.n in Watcher’s third argument, which is a callback function, and continue to do something. Diff algorithm and so on. Let’s start writing the Watcher class: Import Dep from ‘./ dep.js’ let uid = 0 export default class Watcher { constructor(target, expression, Callback) {this.id = UI ++ // Let each watcher instance have its own id this.target = target // Target is the object passed to monitor when creating a new instance (obj) this.getter = ParsePath (expression) // Getter is a function, Call this.callback = callback // callback is the callback passed in this.val = this.get() // get the value of target’s expression}
Update () {this.run()}
Dep.target = this const obj = this.target
Let the value try {/ * note, once here to get the obj expression the value of the attribute, because obj has been observe, So defineReactive is triggered, get() in object.defineProperty is triggered */ value = this.getter(obj)} finally {// after the try block, Target = null // Exit dependency collection} return value is executed regardless of whether an exception is thrown or caughtCopy the code
}
Ps need self-study video can pay attention to B station — BV1zK4y137wr? p=3&spm_id_from=pageDriver