We are using Mobx in one of our projects, and I see frequent use of asFlat and asReference in the code. As per my understanding, asReference fires a change only when the reference is changed but not when any property on the object changes. In contrast, Mobx will track all properties of an object marked as observable (given that those properties were present during object creation). But I don't see any change in behaviour between the two in the code below.
Similarly, asFlat allows the property itself to be observable but not any of its children. Which means that adding a new value to an array marked as asFlat will not fire a change, but changing the reference of array will. However, in the code below, both arrays behave exactly the same. Why is this happening?
Also, what is the difference between asReference and asFlat, as both seem similar?
const {observable, asFlat, asReference, reaction} = mobx;
class Car {
constructor() {
reaction(() => this.colors, () => console.log('colors changed: ',this.colors));
reaction(() => this.colorsAsFlat, () => console.log('colorsAsFlat changed: ',this.colorsAsFlat));
reaction(() => this.config, () => console.log('config changed: ',this.config));
reaction(() => this.configAsReference, () => console.log('configAsReference changed: ',this.configAsReference));
}
@observable colors = [];
@observable colorsAsFlat = asFlat([]);
@observable config = {model : '7 Series'};
@observable configAsReference = asReference({model : '7 Series'});
}
const bmw = new Car();
bmw.colors.push('Red');
bmw.colors[1] = 'Gray';
bmw.colors = ['Black'];
bmw.colors.push('Blue');
bmw.colorsAsFlat.push('Red');
bmw.colorsAsFlat[1] = 'Gray';
bmw.colorsAsFlat = ['Black'];
bmw.colorsAsFlat.push('Blue');
console.log("Initial Config: ", bmw.config);
bmw.config.model = '5 Series';
bmw.config.autopilot = 'true';
bmw.config = { sunroof : 'true'};
bmw.configAsReference.model = '5 Series';
bmw.configAsReference.autopilot = 'true';
bmw.configAsReference = { sunroof : 'true'};
reaction is just used to track changes in the observables and will log the observable property whenever it changes. Here is a fiddle for the same. Observe the console output for this code.
Questions from above code:
- Why
bmw.colors.push('Red')andbmw.colors[1] = 'Gray'did not fire a change (reaction)? bmw.colors = ['Black']fired the reaction but why does thecolorsarray also includes 'Blue' in it in the log when 'Blue' is assigned after 'Black'?colorsAsFlatis firing on same changes ascolorseven though it is declaredasFlat. So it should only fire onbmw.colorsAsFlat = ['Black']as its a refernece change (and it does so), but it also unexpectedly includes 'Blue' color. Why so?- Why does logging
bmw.configprintInitial Config: {autopilot: "true", model: "5 Series"}when these two properties are assigned after theconsole.logstatement? - Why doesn't reaction fire for
bmw.config.model = '5 Series'?. Aren't object properties that were present when the observable object was created observed for changes? configAsReferenceis behaving as expected and is firing a change only when the reference is changed; as the reaction fires only onbmw.configAsReference = { sunroof : 'true'}, which is a reference change.