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/