this tape test reproduces the behaviour that surprised me:
test("toJS toplevel not observable", t => {
const a = mobx.observable({ x: null, y: 3 });
const arr =[a]
const res = mobx.toJS(arr);
t.equal(mobx.isObservable(res[0]), false);
t.end();
})
I think we should always traverse the whole object when doing toJS() even if the top level object is not observable. This is the behaviour that would match it's counterpart- observable which always makes everything observable.
What do you think @mweststrate ? Can I prepare another PR?
Having the same issue I believe (v2.7.0)
observable which always makes everything observable.
Actually that isn't entirely true ... if the object is observable already, it's not traversed.
So toJS behavior is somehow complementary to this - if the object isn't observable already, it's not traversed:
const Mobx = require("mobx");
const ob = Mobx.observable({
arr: Mobx.asReference([])
});
console.log(Mobx.isObservable(ob.arr)); // false
Mobx.observable(ob);
console.log(Mobx.isObservable(ob.arr)); // still false
const nonOb = {
arr: Mobx.observable([])
};
console.log(!Mobx.isObservable(nonOb.arr)); // false
Mobx.toJS(nonOb)
console.log(!Mobx.isObservable(nonOb.arr)); // still false
// read !Mobx.isObservable as isJS()
EDIT:
Maybe Mobx could support implementing:
[mobx.Symbol.observable] (following TC39 Observables syntax)
and
[mobx.Symbol.toJS]
they would be used by observable/toJS during conversion if defined.
@urugator good point. Haven't thought of that.
@capaj the behavior has changed in 2.7 indeed, as toJS only walks the observable parts of a tree, until something is non-observable. This fixes issues related to accidentally trying to clone referred concepts, see e.g. #377 and several other issues as well. A generic clone function is not really the domain of MobX, but rather should lodash be used for such problems (in combination with toJS for example).
@jeffijoe toJS_legacy can be used in 2.7 to get the old behavior still.
Most helpful comment
Actually that isn't entirely true ... if the object is observable already, it's not traversed.
So
toJSbehavior is somehow complementary to this - if the object isn't observable already, it's not traversed:EDIT:
Maybe Mobx could support implementing:
[mobx.Symbol.observable](following TC39 Observables syntax)and
[mobx.Symbol.toJS]they would be used by
observable/toJSduring conversion if defined.