Closed danielkcz closed 5 years ago
Fair enough, thanks for checking it! I think I'm trying to get at something a bit different that maybe isn't best in this thread. The reason it doesn't work is clear to us in that simple example, but in practice this is the type of thing I know I'll be seeing bug after bug in and having to constantly explain/fix. I think the philosophy of "when in doubt use observer" etc from mobx-react is a great approach - it eliminates a whole category of bugs. So I guess to sum it up, yes this all technically works as designed, but I was attempting (maybe poorly) to get at simplicity... i.e. should those patterns where you really have to know what you're doing be reserved for lower-level areas or do we want to be encouraging all those patterns throughout an entire app.
Ok, I think we got too much off the track here. We can generally agree that all three variants of the observer have some use cases and should be kept. It's merely the question of establishing some patterns and recipes which I want to tackle in #115, but could use some help for sure as I am kinda swamped with other stuff.
Fair point, it's all unrelated to the utility hooks :)
So I just recently discovered an interesting platform for investigating pros & cons. Made one regarding observer pattern, so let's try that :)
https://www.kialo.com/differences-with-mobx-observer-pattern-in-react-28353
Merged and published #130 in 1.3.0 version
Accepting PR for 2.0 removing these deprecated hooks.
I'm looking at implementation of useAsObservableSource and it seems concerning that new observable is created for each instance of stateful component: https://github.com/mobxjs/mobx-react-lite/blob/master/src/useAsObservableSource.ts#L11
It it really necessary? What about using something like autorun instead?
useState
will run this function only once, because it's an initializer!
So there's no issue with that.
This is only within one instance of stateful component. I'm talking about multiple instances on page or multiple different components using the same data source
This is only within one instance of stateful component. I'm talking about multiple instances on page or multiple different components using the same data source
Well, that's kinda up to you. If you want to optimize that way, simply store that state inside the context and reuse across the components.
Then what's the point of useAsObservableSource if it only allows for tracking changes within one instance of stateful component? We already have useState for it (or useLocalStore)
It's useful in conjunction with useLocalStore
if you have some values derived from a combination of props and observable state. Read the discussion above, there is brainstorming around this, especially https://github.com/mobxjs/mobx-react-lite/issues/94#issuecomment-482533778
Then what's the point of useAsObservableSource if it only allows for tracking changes within one instance of stateful component? We already have useState for it (or useLocalStore)
If you already have observable data (from a prop, from context or even just a plain "global" observable object), you don't need useAsObservableSource
and changes will be tracked as they always have by observer
/<Observer>
/useObserver
or any reaction that you may declare in your component.
This hook's goal is to create an stable (= will not change throughout the life of the component) reference to an object that you create from unstable (= will change at each render) references. The main usage here is to wrap props, so that you can use them in useLocalStore
and local reactions created with useEffect
without having to recreate them at each render to accommodate to prop changes. This is how hooks are expected to work in general, but this behaviour doesn't work well (and flat out doesn't make any sense with observable data), so we had to find a workaround
I've slept on it and I think that introducing useAsObservableSource
was a mistake if its primary purpose is supporting useLocalStore
. A more "react hooks" way would be to pass property dependencies as second argument as so:
const store = useLocalStore(() => ({
count: 0,
get multiplied() {
return multiplier * this.count
},
inc() {
this.count += 1
}
}), [multiplier])
I also believe that react does this convention on purpose because they plan to extend compiler support (just like newest version of svelte does). So while you might consider such "manual" dependency declaration unpleasant, it isn't necessairly forever as mobx-react-lite could introduce in the future babel plugin that auto-injects property dependencies into useLocalStore as well
As discussed above, the problem with such approach is that you don't want to reset count when multiplier changes.
Op di 30 apr. 2019 18:19 schreef Adam Stankiewicz <notifications@github.com
:
I've slept on it and I think that introducing useAsObservableSource was a mistake if its primary purpose is supporting useLocalStore. A more "react hooks" way would be to pass property dependencies as second argument as so:
const store = useLocalStore(() => ({ count: 0, get multiplied() { return observableProps.multiplier * this.count }, inc() { this.count += 1 } }), [multiplier])
I also believe that react does this convention on purpose because they plan to extend compiler support https://twitter.com/sebmarkbage/status/1122185602839932928 (just like newest version of svelte 3 https://svelte.dev/blog/svelte-3-rethinking-reactivity does). So while you might consider such "manual" dependency declaration unpleasant, it isn't necessairly forever as mobx-react-lite could introduce in the future babel plugin that auto-injects property dependencies into useLocalStore as well
β You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/mobxjs/mobx-react-lite/issues/94#issuecomment-488018042, or mute the thread https://github.com/notifications/unsubscribe-auth/AAN4NBDPHVN2PD34U2Y2DKLPTBWRLANCNFSM4HAQXQOQ .
It doesn't need to you if implement it this way. This just API change
Okay maybe I'm saing things that can't be implemented. Next time I'll support my comment with code
@sheerun In case you would make it like a dependency, there is no way for you to apply that changed value except throwing away whole observable and creating a new one. We would need to provide a way for you to actually merge with the previous state.
For someone who is starting with MobX you are full of ideas :D
I don't know from where the impression that I'm starting with mobx. It's almost 3 years for me..
@sheerun Also note that:
Mobx is all about automatic subscription management (figuring deps out for you).
Deps array is (optional) optimization tool, not a semantic guarantee - that wouldn't be true in this case as missing deps could cause staleness.
If compilation becomes a necessity, more profound solutions are possible (like svelve, elm, effectfuljs...).
@sheerun apologies, your earlier code snippet suggested / implied a full reset to me without further explanation. The PR is much clearer :).
Update
After a lengthy discussion, we have agreed on the removal of
useComputed
anduseDisposable
. TheuseObservable
hook will be renamed touseAsObservableSource
and meant primarily for turning props/state data into observable. These can be then safely used in a new hookuseLocalStore
which will support lazy-init and serve as the main way of constructing observables within a component.Check out a comment with an initial proposal: https://github.com/mobxjs/mobx-react-lite/issues/94#issuecomment-482533778
Time has come to start considering this. There have been some discussions lately that got me convinced these utilities should not have been in a package in first place. I think we got carried away in here, most likely because it felt good to have some custom hook π Ultimately, people might get the wrong idea that to use MobX in React they need to use these specific hooks.
I think it's better to do this sooner than later before people start using these utilities too much and would need to painfully migrate later.
As the first step, I would like to focus on preparing a website dedicated to MobX in React that would show several recipes and DIY solutions. I would like to hear some recommendations on what toolkit would be the best candidate for such a site. Gatsby?
The idea of some separate package with utility hooks is not eliminated, but it should go hand to hand with new docs to thoroughly explain the concepts and not to just blindly use the hook without fully understanding implications.
useComputed
The most controversial and not even working properly. After the initial pitfalls, I haven't used this anywhere. Is someone using it successfully?
useDisposable
As @mweststrate discovered today, there is not much of the benefit to this as the
React.useEffect
does exactly the same. The only difference is access to early disposal function. Personally, I haven't used for anything just yet. I would love to hear use cases if there are any. I am almost ashamed I haven't realized this before and just blindly used it πuseObservable
Probably the most useful out of these three and the most discussed (#72, #7, #22, #69) also. It's clear that it's not only confusing but in its current form, it's wrong altogether. Personally, I have rather used
React.useState
for a component local state which is so easy and doesn't require anyobserver
. There is not much performance gain anyway unless<Observer />
is used. For the shareable state, it seems better to just use Context and build such a state in a way people like. Also, it makes a little sense to be resetting the whole MobX state based on props change.