Above, we speculated on the basic principles of Mobx and simulated the implementation of two core Mobx apis. In this article, we will enter the source code to see how Observable is implemented.
Not simple Observable
An Observable isn’t just a method. It should be thought of as an object.
Mobx definition of observables on the packages/Mobx/SRC/API/observables. Ts:
function createObservable(v: any, arg2? :any, arg3? :any) {}
Object.assign(createObservable, observableDecoratorAnnotation)
export var observable: IObservableFactory = assign(createObservable, observableFactories)
Copy the code
After doing this, an Observable can be called as a method and has these capabilities:
const observable = function(){... } Object.assign(observable,{ box(){}, array() {}, map() {}, set() {}, object() {}, ref: ... , shallow: ... , deep: ... , struct: ... , annotationType_: ... , options_: ... , make_(){}, extend_(){} })Copy the code
The four properties from createObservableAnnotation methods to create objects
{
annotationType_: name,
options_: options,
make_,
extend_
}
Copy the code
The other properties come from the observableFactories object.
The body of an Observable looks like this:
function createObservable(v: any, arg2? :any, arg3? :any) {...if (isObservable(v)) return v
// plain object
if (isPlainObject(v)) return observable.object(v, arg2, arg3)
// Array
if (Array.isArray(v)) return observable.array(v, arg2)
...
return observable.box(v, arg2)
}
Copy the code
Observable calls the corresponding method based on the parameter type:
observable.object
Suppose we call form observables (obj), obj is a plain object, it is the actual call observableFactories. Object, it returns a value is as follows:
extendObservable(
globalState.useProxies === false|| options? .proxy ===false
? asObservableObject({}, options)
: asDynamicObservableObject({}, options),
props,
decorators
)
Copy the code
You can see that the returned value was created from an empty object {}.
, according to whether to use the Proxy to invoke asDynamicObservableObject and asObservableObject respectively to the empty object for processing.
AsObservableObject and extendObservable
AsObservableObject for this added a ${} object mobx properties, it is a ObservableObjectAdministration instance. This object will be called target later
export function asObservableObject( target: any, options? : CreateObservableOptions ): IIsObservableObject { if (hasProp(target, $mobx)) { return target } const adm = new ObservableObjectAdministration( target, new Map(), "ObservableObject", getAnnotationFromOptions(options) ) addHiddenProp(target, $mobx, adm) return target }Copy the code
ExtendObservable associates this target with the OBJ object we passed in.
export function extendObservable<A extends Object, B extends Object>( target: A, properties: B, annotations? : AnnotationsMap<B, never>, options? : CreateObservableOptions ): A & B { const descriptors = getOwnPropertyDescriptors(properties) const adm: ObservableObjectAdministration = asObservableObject(target, options)[$mobx] startBatch() try { ownKeys(descriptors).forEach(key => { adm.extend_( key, descriptor[key as any],true) }) } finally { endBatch() } return target as any }Copy the code
extendObservable
Will pass us inobj
Object’s key and corresponding descriptor, passObservableObjectAdministration
The instanceadm
theextend_
Method, added to target.
To be continued
By this point, the Observable method is all sorted out, but we don’t get a glimpse of Mobx’s underlying principles. And we also met a strange object ObservableObjectAdministration. Observable Manager, as the name suggests, is a key class in Mobx, and it is this class that will lift the veil from Mobx.
Listen to the breakdown next time.