Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

intercept() and observe() don't track nested observables #302

Closed
antitoxic opened this issue Jun 3, 2016 · 8 comments
Closed

intercept() and observe() don't track nested observables #302

antitoxic opened this issue Jun 3, 2016 · 8 comments

Comments

@antitoxic
Copy link

var appState = observable({
    counter: 2,
    todos: [{
        title: 'Submit mobx issue',
        done: false
    }]
})
intercept(appState, function(change) {
    console.log(change)
    return change;
})
observe(appState, function(change) {
    console.log(change)
    return change;
})
appState.todos[0].title = "Get stuff done";

No output. Bug or feature?

@AriaFallah
Copy link

AriaFallah commented Jun 3, 2016

Intended unfortunately. Although I would like a way to be able to deeply observe as well. Currently there is spy that would work, but that is for all observables instead of a nested hierarchy.

@antitoxic
Copy link
Author

So, autorun tracks only what properties that has been accessed (just like observer I guess)

Make sense but again I was a bit surprised. I will try to do a pull request for the docs and add a simple clarifying sentence.

@antitoxic
Copy link
Author

Ah completely messed up previous comment. I meant to add that I got confused with autorun as well.

As for intercept() and observe() I will also include some clarification and the docs and make a pr.

I also wish there was a nested option for () and observe(). Otherwise this forces me to break down my state to stores on every nested object/array.

@mweststrate
Copy link
Member

Doc PR's are more then welcome!

If you need to deep observe, I recommend using autorun or reaction. Did that fit? It is also good to note that you can make observe handlers generic; e.g. reuse the same callback over and over again because the causing object is always in change.object. (You still need to register them all though, so that is why I usually opt for autorun / reaction

@matthewmueller
Copy link

matthewmueller commented Nov 15, 2016

so why this is intentional? is there a limitation in intercepting nested values? you can also listen on:

appState.todos.intercept(fn)

but maybe there's harm in handling both?

edit: nevermind on the intercept example above, that only works on things like push(...)

@AriaFallah
Copy link

@matthewmueller

From what I know, intercept basically works like this, and thus can't look any deeper into your object:

spy(function(change) {
  // references match
  if (change.object === myObject) {
    // Do stuff with change info
  }
})

I experimented a lot with deep observation, and short of adding a non-enumerable field marking the parent of a given observable (which is in my opinion too much work), it didn't work well.


A possible alternative is wrapping all the changes you want to intercept inside of action, and then intercepting the action like so

const myObject = { a: 1 }

const modifyObject = action('modify', function() {
  myObject.a = 5
})

spy(function(change) {
  // action which modifies all your objects detected!
  if(change.type === 'action' && change.name === 'modify') {
    console.log(myObject) // myObject before it's changed!
  }
})

@mweststrate
Copy link
Member

intercept and observe are low level api's you should hardly need. Is it a problem that cannot be solved by e.g. reaction @matthewmueller? observe has many drawbacks like for example not respecting transactions.

The reason it doesn't deep observe is that it it cannot be generalized, if you have a cyclic structure deep observing will either utterly crash or be very expensive to prevent that. MobX doesn't make assumptions on your data structures and hence cannot generalize this. In contrast to for example mobx-state-tree, which does support deep observing out of the box, but as a tradeoff you are required to limit yourself to using data trees instead of data graphs.

@matthewmueller
Copy link

matthewmueller commented Nov 15, 2016

ah okay, thanks for the info & links guys. I think I'm definitely leaning more towards what you're doing with mobx-state-tree, basically trying to combine tcomb with mobx, using intercept to reject invalid state updates.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants