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

Deeply observe object #32

Open
naturalethic opened this issue Aug 16, 2018 · 12 comments
Open

Deeply observe object #32

naturalethic opened this issue Aug 16, 2018 · 12 comments

Comments

@naturalethic
Copy link

I would like to be able to observe for any change in a deep object.

@minicuper
Copy link

you can

@naturalethic
Copy link
Author

Source:

const { observable, observe } = require("@nx-js/observer-util")

const o = observable({
  foo: {
    bar: {
      baz: 1
    }
  }
})

const ob = observe(() => {
  console.log(o)
})

o.foo.bar.baz = 2
o.foo.bar.baz = 3

Complete output:

{ foo: { bar: { baz: 1 } } }

@CheloXL
Copy link

CheloXL commented Sep 15, 2018

Proxies are created on demand, so the above code would never work, since no proxies are created for foo, bar and baz. To do so, the library should have to walk the entirely tree and create a proxy for every object on it on registering the observable.

If you need that functionality, you can implement that yourself by doing exactly that: recursively walk the tree and observing every property.

@naturalethic
Copy link
Author

Ok, just for background this was in the context of react-easy-state, using a third party widget that takes a tree of data, i needed the widget to update whenever any element of the tree updates. I ended up using a different means for this case. It does seem like observing an entire tree is out of scope for react-easy-state.

Thanks.

@solkimicreb
Copy link
Member

Hey, this should work, I will check it in a sec.

@solkimicreb
Copy link
Member

Sooo, this lib (and easy state) intercepts everything that 'can be intercepted'. Built-in functions in JS are sometimes implemented in none JS code (C++ for example). The above console.log statement is one of these cases, it recursively fetches the object keys in none JS code, which Proxies can not intercept. Consequently, the lib does not register the set of observable keys.

You can try this code for example and it will work.

const { observable, observe } = require("@nx-js/observer-util")

const o = observable({
  foo: {
    bar: {
      baz: 1
    }
  }
})

const ob = observe(() => {
  console.log(JSON.stringify(o))
})

o.foo.bar.baz = 2
o.foo.bar.baz = 3

JSON.stringify is accessing the keys in JS, so the lib can intercept the observable get operations. Sadly I can not give any guarantees about the behavior of built-in functions, their behavior with Proxies is not yet specified by the spec. Last time I checked observe(console.log) was working in Node.

Anyway, people rarely want to observe built-in functions, they usually observe 'normal JS code', which works all the time.

I hope this helps. (Could you include a small repro of your easy-state issue?)

@solkimicreb
Copy link
Member

Your problem with easy-state was probably something very different.

I see you were passing a tree of data to a third party component and expected it to re-render when the data tree was mutated. In this case the issue was that the third part component was not a view (observer). It did not know that it should re-render when the data changes.

Your component was not using the data (it was not accessing parts of it), it just passed it on to the third party component. That component used the data, but it was not a view.

This seems the be a pretty common use case, I will try to think about a good alternative for it by tomorrow.

@matthew-dean
Copy link

Wait, nested objects aren't made observable? Why not?

@matthew-dean
Copy link

From react-easy-state docs: Use nested properties, computed properties with getters/setters, dynamic properties, arrays, ES6 collections and prototypal inheritance

@solkimicreb
Copy link
Member

solkimicreb commented Nov 13, 2018

@matthew-dean

Wait, nested objects aren't made observable? Why not?

How did you come to this conclusion? Nested objects are made observable on demand.

@manico
Copy link

manico commented Aug 7, 2019

Is there an example how to observe every property in nested object?
It seems that you have to explicitly use proxy observable inside observe function (value cannot be passed to it).

@3cp
Copy link

3cp commented Aug 1, 2021

BTW, some examples in this repo's README is wrong.

observe(() => console.log(person), { scheduler: ... });

That log only observes person itself, not nested properties. Should be:

observe(() => console.log(JSON.stringify(person)), { scheduler: ... });

Or some kind of explicit access of person.name and person.age.

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

No branches or pull requests

7 participants