-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Atom and onBecome(Un)Observed #992
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
Comments
Fiddle presenting the problems: https://jsfiddle.net/wv3yopo0/1212/ |
I've noticed that However isPendingUnobservation = true; // for effective unobserving. BaseAtom has true, for extra optimization, so its onBecomeUnobserved never gets called, because it's not needed At the same time provides implementation for that never called public onBecomeUnobserved() {
// noop
} And comment: |
The api is currently not designed to directly extend / replace / monkey patch the I hope that explains! what is your concrete use case for which you need to attach to the handlers of an observable value? |
In general any resource managment - allocating/disposing connections/pools/continuous tasks/timers/data/memory/monitoring/... Why
Currently there is a workaround: get data() {
this.atom.reportObserved();
return this._data;
} The complete example can be seen here However this solution doesn't make much sense either, because:
Note that you could easily map the resource allocation/disposal only to a subset of consumers of particular observable. All you have to do is to expose an adapter for these specific consumers: // Let's say I want to run timer only when React components use the data
const data = observable("text"); // don't expose to components
const adapterForReactComponents = computed(() => data.get()) // expose to components
// hook resource management only to observable exposed to components
onBecomeObserved(adapterForReactComponents, startTimer);
onBecomeUnobserved(adapterForReactComponents, stopTimer); |
@urugator the mobx utils like Otherwise the only clean way to support this, is exposing |
For However I like to think about the I have been also wondering if it would make sense or be useful to attach the handlers for a whole object graph and treat it as one. So observed handler would be called when the first observable from the graph become observed, and unobserved handler would be called when all observables from the graph become unobserved... |
That is something you cannot reason about if you don't know about the data structure. Two objects refering to each other would kill this approach. You need a tree for that, like MST. However, if you design your data to be a tree, you just need to listen to the root node events, as accessing a deeper node should cause the root node to be accessed and observed as well in a properly design object, in other words, you can only observe |
@urugator / @jamiewinder ok, there are too many good use cases where Would you guys willing to help me out by writing unit tests for these functions? |
Certainly, if I can use this to implement the keepAlive and fromAjax functions then I'll add some unit tests (though async tests can be a bit hairy). I think some basic general-case unit tests of the basic onBecome(Un)Observed should be fairly simple too. |
@jamiewinder cool! Just added you to the organization, so you can create your own branches :) Ping me when ready :) |
I'm about at the point where I might be able to put some time to this. Was the idea that you'd implement the low-level |
@jamiewinder that would be great :D. Feel free to start on tests for proper TDD ;-) |
@jamiewinder @urugator I think these functions make the most sense to only be called when a real observer relationship is established (as in: some reaction is (indirectly) going to use the observable). A downside is that this will be inconsistent with the on(Un)Observed handlers of atoms, which also trigger on incidental reads. Here are some initial tests: https://github.com/mobxjs/mobx/pull/1270/files#diff-de3e9f045a27674fe5620294772bd6c4 Sorry for the late follow up. But I agree that this is a missing low-level api that allows for very powerful abstractions. |
I don't follow, what are incidental reads? |
reads, but not from inside a reaction. Like `computed.get()` versus
`autorun(() => computed.get())`
Op di 12 dec. 2017 om 02:21 schreef urugator <[email protected]>:
… I don't follow, what are incidental reads?
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#992 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/ABvGhJ3mg3mE78BvPvwjmQXjvnqFXWhMks5s_dUZgaJpZM4NZfSL>
.
|
untracked reads
Op di 12 dec. 2017 om 08:36 schreef Michel Weststrate <[email protected]
…:
reads, but not from inside a reaction. Like `computed.get()` versus
`autorun(() => computed.get())`
Op di 12 dec. 2017 om 02:21 schreef urugator ***@***.***>:
> I don't follow, what are incidental reads?
>
> —
> You are receiving this because you commented.
> Reply to this email directly, view it on GitHub
> <#992 (comment)>, or mute
> the thread
> <https://github.com/notifications/unsubscribe-auth/ABvGhJ3mg3mE78BvPvwjmQXjvnqFXWhMks5s_dUZgaJpZM4NZfSL>
> .
>
|
I see, I wasn't aware that if (this.atom.reportObserved()) {
return this.currentDateTime;
} else {
// apparantly getTime was called but not while a reaction is running.
// So, nobody depends on this value, hence the onBecomeObserved handler (startTicking) won't be fired Seems weird, is this behavior even intended? |
Is |
@urugator yeah there is some uncannyness in the current behavior of |
Idea:
atom.reportObserved; // explicitely stating it's observed, reaction or not, call onBecomeObserved
atom.reportUnobserved; // explicitely stating it's unobserved, reaction or not, call onBecomeUnobserved
atom.reportAccessed; // call onBecomeObserved only when inside of tracking context (actually call reportObserved)
|
This has been fixed now in the MobX 4 branch (see #1321) The behavior is now as follows:
|
First some simplified self-explanatory code of what I was trying to accomplish:
The point is the ability to hook additional resource management to an existing atom, instead of creating another one and synchronizing their subscription/unsubscription through a common getter.
However it doesn't work for multiple reasons, which can be expressed by following questions:
Why
onBecomeObserved
is not defined onIObservable
interface similary toonBecomeUnobserved
?Why
BaseAtom
doesn't provide default implementation foronBecomeObserved
similary toonBecomeUnobserved
? (note the comments)How so, that
getAtom(observable("hello")).onBecomeObservedHandler/onBecomeUnobservedHandler
(both) returns undefined? Shouldn't they be functions?If I replace
onBecomeObserved/onBecomeUnobserved/onBecomeObservedHandler/onBecomeUnobservedHandler
on atom obtained bygetAtom(observable("hello"))
it seems like non of it gets called whenautorun
is created/disposed (replacement is done before the reaction is created).The text was updated successfully, but these errors were encountered: