mobx-state-tree
mobx-state-tree copied to clipboard
Child objects containing a reference maybe undefined in afterCreate() or afterAttach()
Bug report
- [x] I've checked documentation and searched for existing issues
- [x] I've made sure my project is based on the latest MST version
- [x] Fork this code sandbox to reproduce. (execute unit tests)
Sandbox link or minimal reproduction code
https://codesandbox.io/s/festive-rain-7rtp1
=> Execute the jest unit tests. Second unit test "load DataModel from rootSnapshot" fails
Describe the expected behavior
I have a model with 4 levels of data in the following format:
export const ItemModel = types.model("ItemModel").props({
id: types.identifier,
name: types.string
});
export const ItemContainerModel = types.model("ItemContainerModel").props({
item: types.safeReference(ItemModel)
});
export const ObjectModel = types.model("ObjectModel").props({
itemContainer: types.maybeNull(ItemContainerModel)
});
export const DataModel = types
.model("Data")
.props({
item1: ItemModel,
object1: types.maybe(ObjectModel),
object2: types.maybe(ObjectModel)
})
.actions((self) => {
return {
afterCreate() {
// here self.object2?.itemContainer is DEFINED while self.object1?.itemContainer is UNDEFINED
}
};
});
export const RootModel = types.model("RootModel").props({
data: DataModel
});
I expect in DataModel.afterCreate() that self.object1.itemContainer to be defined, like self.object2.itemContainer
Describe the observed behavior
In DataModel.afterCreate() self.object1.itemContainer is NOT defined. whereas self.object2.itemContainer IS defined.
I suspected an issue between "late loading" and "references resolving" but I have tried several uses of types.late(), and nothing solved it.
If I replace item: types.safeReference(ItemModel) with item: types.string, it behaves like it should of course (eg: self.object1.itemContainer is defined), but item is no more a reference ;-) I need it to be a reference.
Please note that object1 and object2 are 2 objects with exactly same content, same model.
If I add object3 with same content, object1.itemContainer is still undefined, but not object2.itemContainer nor object3.itemContainer.
What is strange is that the concerned object (root.data.object1 in the second unit test in codesandbox), is well defined AFTER store has been fully created: (after const root = RootModel.create(rootSnapshot)call)
Fork this code sandbox to reproduce. (see unit tests)
Note that the issue does not happen if when there is only 3 levels (data > itemContainer > object1 instead of 4 levels in root > data > itemContainer > object1) (See 1st unit test load DataModel from rootSnapshot.data)
I'm blocked since days with this issue ;-)
thxxxx in advance !!!
Edit:
Same behavior with afterAttach().
To reproduce in codesandbox, simply replace afterCreate() with afterAttach() in unit tests.
More generally, it seems that objects that contain at least one reference, and are "deep" in the tree are seen "undefined" in parents' afterCreate() calls.
Hi @EmilTholin
Yes, same behavior with afterAttach(). I forgot to mention it.
This problem (or one very much like it) can also occur after a model with a reference has been created and the (trans)action has completed. A suitable work-around in my case was to set the value of the reference twice. For example:
const node = Model.create(values)
node.reference // <-- incorrectly undefined
node.setReference(value)
node.reference // <-- correctly resolves
Hey @goulkreek - I'm sorry it's been a while since we saw some activity on this MST issue. It does look like https://github.com/mobxjs/mobx-state-tree/pull/1952 might fix or improve this problem. I'm not exactly sure if and when that's on the roadmap (there are some concerns about the breaking nature of the change), but for now, I'm going to label this issue as "has PR", and keep it open. Hopefully we can figure it out soon!