I need to replace data in my observable object when I get a new dump from the socket:
class Store {
@observable data = { foo: 'bar' }
replaceFromDump(newData) {
this.data = newData
}
}
const store = new Store()
store.replaceFromDump({ foo: 'bar' })
// { foo: 'bar' } can be a huge amount of JSON
However, I noticed performance hits when the data object scales, probably because MobX will trigger reactions everywhere even if some properties/values are identical.
Is there a "smarter" way? - I’m thinking that f.ex only replacing the affected parts of the object would be better than replacing the entire observable?
I made a small demo here explaining what I mean: https://jsfiddle.net/yqqxokme/.
Replacing the object causes new reactions, even if the data is exactly the same (expected). But I’m sure there is a way to only mutate the affected parts of the data object like in the merge()
function.
So here are few things and cases. I have changed the dump function to below to simulate changes
variations = [
{foo: 'bar'},
{foo: 'bar'},
{foo: 'bar2' },
{foo: 'bar2' },
{foo: 'bar2', bar: {name: "zoo"} },
{foo: 'bar2', bar: {name: "zoo"} },
{foo: 'bar2', bar: {name: "zoo2"} },
{foo: 'bar2', bar: {name: "zoo2"} },
{foo: 'barnew', bar: {name: "zoo2", new: "yes"} },
{foo: 'barnew', bar: {name: "zoo2", new: "no"} },
{foo: 'barnew', bar: {name: "zoo2", new: "no"} }
]
i=0;
dump = () => {
i++;
i = i%variations.length;
console.log("Changing data to ", variations[i]);
store.replaceFromDump(variations[i])
}
Using extendObservable
Now if you use below code
replaceFromDump(newData) {
extendObservable(this.data, newData)
}
And run it through the dump cycle, the output is below
The event for bar
won't start raising until you get a change to foo
, which happens on below change
{foo: 'barnew', bar: {name: "zoo2", new: "yes"} },
Outcome: New keys can only be observed existing observable keys change
Using map
In this we change the code like below
@observable data = map({
foo: 'bar'
})
replaceFromDump(newData) {
this.data.merge(newData)
}
Outcome: The data is merge only and won't get deletions. You also will get duplicate events as it is a merge only option
Using Object Diff
You can use an object diff library like below
https://github.com/flitbit/diff
You can update the code like below
@observable data = {
foo: 'bar'
}
replaceFromDump(newData) {
if (diff(mobx.toJSON(this.data), newData)){
this.data = newData;
}
}
Outcome: The events only happen when data change and not on re-assignment to same object
Using Diff and Applying Diff
Using the same library we gave used earlier, we can apply just the changes needed
If we change the code like below
replaceFromDump(newData) {
observableDiff(toJSON(this.data), newData, d => {
applyChange(this.data, newData, d);
})
}
If run the above, we get following output
Outcome: Only changes to initial set of keys is observed, give you don't delete those in keys in between
It also gives you diff in below format
{"kind":"E","path":["foo"],"lhs":"bar2","rhs":"barnew"}
{"kind":"N","path":["bar","new"],"rhs":"yes"}
Which means you can have better control of things based on field names when you want
Below is the fiddle that I used, most code commented but in case you need to look at the imports use below
https://jsfiddle.net/tarunlalwani/fztkezab/1/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With