I need a pattern in which a view returns an object users can subscribe to before that entity exists in the store.
For example, something like this should work even before the real post 17 is added to the store:
<Author name={store.entity('post', 17).author.name} />
For that, I'm using a view with resolveIdentifier and if the entity is not ready yet, I return a "skeleton" object.
This approach seems to work great, except that the resolveIdentifier is firing twice when it founds the item instead of once. I don't know really why.
This is the simplest code I could come up with:
https://runkit.com/luisherranz/mst-resolve-identifier
const Post = types.model('Post')
.props({
id: types.identifier(types.string),
ready: true,
title: types.string,
})
const UnknownPost = id => ({
id,
ready: false,
title: null,
})
const Model = types.model('Model')
.props({
posts: types.array(Post),
})
.views(self => ({
post: id => resolveIdentifier(Post, self, id) ||聽UnknownPost(id)
}))
const model = Model.create()
unprotect(model)
model.posts.push({ id: 1, title: 'I am the post 1' })
console.log(`post 1 ready: ${model.post(1).ready}`) // Should be true: OK
console.log(`post 2 ready: ${model.post(2).ready}`) // Should be false: OK
let count = 0
mobx.autorun(() => {
console.log(`post 3 ready: ${model.post(3).ready} (autorun executed ${count++} times)`)
})
model.posts.push({ id: 3, title: 'I am the post 3' }) // Should update autorun state to true
This code fires these logs:
"post 1 ready: true"
"post 2 ready: false"
"post 3 ready: false (autorun executed 0 times)"
"post 3 ready: false (autorun executed 1 times)" // <-- ???
"post 3 ready: true (autorun executed 2 times)"
By the way, that code is a simplification. The reason I'm using this pattern is because the Type of the entity is not known until the entity is received. It may be Post, Taxonomy, Author, etc.
By the way, what would be the approach to debug something like this? I tried whyRun() but nothing appeared.
I think you can do this when you use types.map, as that one can track the existince of an entry before it exists.
I'm going crazy speed through issues right now though, so I didn't read very carefully so I might have missed the actual question ;-).
I'll try to reproduce it in React, using a codesandbox 馃憤 鈽猴笍
There you go!
https://codesandbox.io/s/1ymqvpq214
Mobx is triggering invalidation twice when the array is updated.
I think the issue is that you are using an unprotected model rather than an action
Actions create a transaction, which means it will only trigger one change once all the operations inside the action are finished.
After I changed it to use a "addPost" action it renders 2 times
https://codesandbox.io/s/qkynzvoqpw
That being said, I don't get why resolveIdentifier is generating a reaction when being called...
@mweststrate shouldn't resolveIdentifier be marked as non tracking or some such to avoid this?
Ah nevermind, it doesn't
Apparently it is reacting twice because:
[mobx.trace] 'Reaction@401' is invalidated due to a change in: '[email protected]?'
App rendered: 2 times
[mobx.trace] 'Reaction@401' is invalidated due to a change in: 'ObservableArray@413'
App rendered: 3 times
Most helpful comment
Ah nevermind, it doesn't
Apparently it is reacting twice because: