Closed mweststrate closed 6 years ago
long live the MobX
hopefully it could defeat Redux in one day
bq. Proxy arrays, kill faux array @mweststrate, do you really think of dropping IE support? :-( My granny wont be able to visit my website :-(
@andykog I think 3.0 should be maintained still, but want to prepare for the future as well. Promised for a long time now that certain issues will be fixed when proxies are available, and their support is getting more decent now :)
@mweststrate Although we do have some clients who use IE11 explicitly, I do very much support going all in with Proxies
for mobx. I'm really excited about them and think they will make the core a lot simpler.
Not everybody is so lucky that they can ignore IE users. You can't tell managers that we have to drop about 4% of customers because that will make mobx core simpler. This puts many user in a position where they have to decide wheather they gonna stick to an older mobx version or use something different for their apps. My opinion is that this is to early for switching to proxies.
Compatibilty of:
I don't think I would be able to switch immediately to v4 but I would support using proxies and Map anyway, it's not like 3.0 is going to stop working.
About 5% of our traffic is still stuck on IE. Regardless, I think it's a really cool idea to start exploring the new proxy features. I think we should be super duper explicit about what v4 is all about. We may want to call it mobx-next or something. I do worry that if we wanted to make significant changes to 3.x we'd have to jump past v4. That could be a little funky.
On Thu, Jul 6, 2017 at 2:56 AM, Vincent Prouillet notifications@github.com wrote:
Compatibilty of:
- proxy: http://caniuse.com/#search=proxy
- Map: https://developer.mozilla.org/en/docs/Web/JavaScript/ Reference/Global_Objects/Map
I don't think I would be able to switch immediately to v4 but I would support using proxies and Map anyway, it's not like 3.0 is going to stop working.
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/mobxjs/mobx/issues/1076#issuecomment-313324108, or mute the thread https://github.com/notifications/unsubscribe-auth/AAIrch_yNRH0QHVYvPv7SFJWuSX2Mfz_ks5sLJMdgaJpZM4ONAsS .
-- -Matt Ruby- mattruby@gmail.com
+1 for mobx-next
, thought about that as well
I could be wrong, but I think
- Maps only supporting primitive keys and Sets not being present
can be implemented now without any loss of browser support (with a polyfilled ES6 Map)? If so, it might be worth this - and any other breaking additions which needn't affect browser support - being the basis of v4, and v5 (or mobx-next) forming the basis for the big move to using Proxy?
https://github.com/ascoders/dynamic-object
here's an object observer with proxy that features similar functionality like mobx, using almost purely Proxy. Indeed the project is written by a Chinese, hence I doubt your ability to read the documents and comments, but you guys can take it as a code reference.
I would be against mobx-next
that sounds like it is a completely new API etc. I don't really see the issue with using v4 for breaking changes, there are polyfills for Map and maybe for proxy (https://github.com/GoogleChrome/proxy-polyfill). v3 will still work and would likely be in maintenance mode
Some quick notes:
expr
to accept options object (like computed
) instead of scope
(breaking)computed/reaction
it's called context
, in autorun/action/when/autorunAsync/spy
it's called scope
(non-breaking)dispose
(reaction object) as a second argument to reaction
's sideEffect
callback
(non-breaking)@urugator tnx!
Also: Upgrade to latest TS
Can we avoid "dispose" somehow, for example storing listeners to WeakMap with observable as a key?
pseudocode:
const map = new WeakMap()
observe(obj, listener) {
map.set(obj, listener)
}
Managing reactions/autorun disposal is my one difficulty with Mobx. Especially when the autorun is on something other than a component (and thus without an unmount/dispose...)
Having struggled recently with async computed functionality, I woukd propose it out of the box.
@rasdaniil +1
Better, clearer support for async, both for computed and for action, would be high on my list. I don't know how feasible it is to improve, but runInAction
feels very kludgy to have to use after every await in an async action.
Check the recently added asyncAction in mobx-utils package! Removes the clumsiness
Op do 27 jul. 2017 17:21 schreef Andrew Metcalf notifications@github.com:
@rasdaniil https://github.com/rasdaniil +1
Better, clearer support for async, both for computed and for action, would be high on my list. I don't know how feasible it is to improve, but runInAction feels very kludgy to have to use after every await in an async action.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/mobxjs/mobx/issues/1076#issuecomment-318394878, or mute the thread https://github.com/notifications/unsubscribe-auth/ABvGhFo-5r6a8qx8B2X2gRd4TUazpR5Nks5sSKsAgaJpZM4ONAsS .
@andykog
You can't tell managers that we have to drop about 4% of customers
MobX releases:
By the time MobX v4 is released, IE usage will be lower. + a few more months because you prefer a bit of dust on new things + the time it takes to switch to v4 (upgrade code, test, document, release) => IE will be even lower
Voilà
@stevefan1999 Redux is OK but still, I do get quite intrigued when I listen as an argument that Redux is for large apps and MobX for small/medium. Not to mention that after a while the amount of files and complexity a Redux based project has to deal with is absurd.
@mweststrate 👍 for killing faux arrays
Good time to looking for the future. I approve the plan of switching to proxies underneath. Besides, React 16 requires Map & Set in runtime environment and it's mandatory.
@OshotOkill - But Map and Set can be polyfilled. Proxy cannot.
@jamiewinder But wouldn't the existing partial polyfill for Proxy cause a rewritten version of mobx to behave just like the current version does (i.e. new properties are not tracked)?
Then mobx4 could just have a compatibility flag that disallows adding new properties to objects and browser compatibility would stay the same.
@phiresky I'm not really sure what the extent of the limitations of that polyfill are apart from the ones you highlighted. One that does start out is the faux array issue of MobX - observable arrays are not arrays. If MobX were to rely on a proxy polyfill, then we'd be in an ever more precarious position where an observable array may or may not 'be' an array depending on whether you're using the polyfill.
I think the switch to proxies should be absolute. i.e. if you need to support non-proxy browsers, then I'm afraid you'll have to stick to the previous version. However, I'm very likely one of those people who'll have to do this, and I'm missing some of the other features that are hoping to be added such as non-string keyed observable maps which can be added but will be a breaking change.
It'd be nice (though I wouldn't presume to ask for it) to see a MobX 4 that adds these features (and require polyfilled Map, Set), and a MobX 5 that forces you to use Proxy, but this might lead to confusion and having to maintain two active versions. So I'm not sure.
Also interesting; when will the new babel decorator implementation be ready? Should 4.0 be based on the old or new implementation (and semantics).
Op ma 4 sep. 2017 om 10:44 schreef jamiewinder notifications@github.com:
@phiresky https://github.com/phiresky I'm not really sure what the limitations of that polyfill apart from the ones you highlighted. One that does start out is the faux array issue of MobX - observable arrays are not arrays. If MobX were to rely on a proxy polyfill, then we'd be in an ever more precarious position where an observable array may or may not 'be' an array depending on whether you're using the polyfill.
I think the switch to proxies should be absolute. i.e. if you need to support non-proxy browsers, then I'm afraid you'll have to stick to the previous version. However, I'm very likely one of those people who'll have to do this, and I'm missing some of the other features that are hoping to be added such as non-string keyed observable maps which can be added but will be a breaking change.
It'd be nice (though I wouldn't presume to ask for it) to see a MobX 4 that adds these features (and polyfill Map, Set), and a MobX 5 that forces you to use Proxy, but this might lead to confusion and having to maintain two active versions. So I'm not sure.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/mobxjs/mobx/issues/1076#issuecomment-326903242, or mute the thread https://github.com/notifications/unsubscribe-auth/ABvGhLyuvLuVPmNxWFW0_n_1YCJv5Bg-ks5se7h7gaJpZM4ONAsS .
For implementation details see https://github.com/ascoders/dob, #776
Just a quick note, because I see people mentioning only IE here. React Native is still not supporting Proxies, which is more important then IE in my opinion (other platforms are fine). Does anyone know when they plan to start supporting them?
@solkimicreb As I know Proxy supported in iOS starting from 10.0. I didn't tested yet but it should be available on iOS because React Native uses system JSCore. On Android Proxies is not supported yet.
Make use of valueOf
in comparer.structural
see #1118
About Proxies on React Native. I am pretty sure they are still not supported: https://facebook.github.io/react-native/docs/javascript-environment.html
@mweststrate Hi, what about using Proxy only in development, to check for uncorrectly used keys or unexistant ones?
That way would improve developer experience and detecting common errors, but without dropping support for old browsers!
About Maps: I actually liked how users are forced to use Map with dynamic keys, that sounds lile a good practice in general JS!
I tried proxy-polyfill, but there are some unstable problems in the ie environment, and can not support deleteProperty, resulting in missing functionality.
So if 4.0 is no longer compatible ie it may be a reliable decision.
@mweststrate thanks for mentioning the library I wrote, If you can support the decorator, it may be easier to understand and more convenient to write:
@observable
class MyStore {
name = 'ascoders' // Automatic observable
articles = [] // Automatic observable
}
@solkimicreb I tested Proxy in React Native on iOS and it works. Big disadvantage Proxy is not supported in React Native on Android and there is no plans to support it in the near future.
UPDATED: I found info JSC may be upgraded for Android in React Native in few months. But there is no real ETA though. In any case we can recommend to use custom JSC in readme if this does not happen before the 4.0 release.
Hi, what about using Proxy only in development,
@caesarsol IMO it is bad idea because something can work in dev but don't work in prod and vice versa. I prefer keep dev and prod environments as close as possible to prevent some strange errors. This is very actual for JS with tons of polyfils and translators.
The idea to use Proxy for dev environments to detect access to non-existing keys of objects and warn developer about it looks good for me! It will conver mos frequent developer error with mobx.
@farwayer that would be only for warning the developer, not to add functionality! So the behavior wouldn't be forked :)
@Strate thanks!
@farwayer Thanks for the info! That's pretty good news 🙂
Other proposed changes:
extras
namespace for better tree shakingspy
. (Does anybody really use that? It seems so far mainly be used for the general flow; actions and reactions). Improved plan:
FIrst split mobx
into mobx
and mobx-core
packages. So that the future and current api are powered by the same package. Would also be great for people who hate the current mobx api with faux arrays, side-effectful getters etc etc. They still could leverage the algorithms behind mobx and build their own library on top of atoms etc.
FYI Vue.js 3.0 (or Vue.js 2.6-next) will use ES6 Proxy: https://blog.cloudboost.io/reactivity-in-vue-js-2-vs-vue-js-3-dcdd0728dcdf
FIrst split mobx into mobx and mobx-core packages
I wanted to suggest something like that, but then I wasn't sure what exactly can be reused and whether some adjustments won't be required. So I thought it may be better to came up with proxy implementation first and then try to identify the common parts and split the package.
@farwayer @solkimicreb @mweststrate
i haven't tried it but the latest release of Expo ("pre-compiled react-native") claims to come with an updated Android JavaScriptCore including among others proxy-support ( https://blog.expo.io/expo-sdk-v22-0-0-is-now-available-7745bfe97fc6 ).
Updated the Android version of JSC to be closer to iOS 10.3’s JSC. Features like WeakMap can be used natively on Android and iOS. On Android and iOS 10+, more features like Proxies are supported.
If I've understood it correct, native proxy support will fix all of mobx quirks when it comes to observing and reacting to more complex data?
@strate yeah detecting an extra property on an observable should be a feature added to the current semver version of MobX. It would catch quite a few developer errors. Although there might be people who do this on purpose. Maybe do the check only in strict mode?
Proposal for a cleaned up observable API:
--- Current
@observable
@observable.ref
@observable.deep
@observable.shallow
observable.box
observable.shallowBox
observable.object
observable.shallowObject
observable.array
observable.shallowArray
observable.map
observable.shallowMap
extendObservable
extendShallowObservable
@computed
@computed.struct
@computed.equals
@action
@action.bound
--- New
@ref // just stores an observable reference
@collection // make any collection it receives observable (1 level deep), objects, arrays, Maps, Sets. Also accepts `null` and `undefined`
@deepObservable // like current `observable`. makes anything deeply observable
ref(value, opts) // creates a boxed observable, with .get / .set
collection(value, opts) // creates an observable wrapper around collection (does not accept `null` / `undefined`)
extend(thing, props, opts) // like extendShallowObservable / extendObservable
@computed
@computed.struct
@computed.equals
@action
@action.bound
type opts = {
deep? = false,
name?: string
// dunno what more...
}
I can't say I'm keen on the renames. I was a big fan of this API change in MobX 3 as it described they describe the intent perfectly.
@ref
implies reference, but nothing about its observable nature. Likewise for @collection
. Having these things hang off of observable
makes it obvious.
We might need mobx-compat after the observable
=> ref
refactor
I have to say I also like having all the different kinds of observable scoped in observable
. Also your list is missing observable.struct
?
In fact, why is computed not also scoped in observable? observable.computed
would make sense :)
The thing I think would make sense to change is to prevent usage of observable() for both primitives and objects, because it's weird that observable({a: 1})
returns something that looks like {a: 1}
but observable(1)
creates an object with {get: () => 1, set: val => void}
, I'd just forbid that.
It's also pretty confusing when starting out that observable(classInstance)
creates an observable.ref
instead of a deep observable.
Also I think all isMobxModifierDescriptor
things work kind of confusing: observable.ref() is a completely different kind of thing than observable.box (you must ref() within another observable, and the opposite for box), but only when not used as a decorator.
I also think shallow
is a far clearer name than collection
. Renaming observable
to deepObservable
might be a good idea, not sure.
Here's how I would change the API:
observable(x)
-> deeply observe all properties of x. if x is a primitive,
null or a class instance then throw an error
@observable x = ...
-> deeply as above, but also allow what's basically a ref (primitives, null, class instances, etc.)
observable.shallow
-> error, modifier are a separate API. Before, I would think
observable.shallow({a: {}, b: {}}) would give me an object with
observable references to a and b, but it doesn't.
@observable.shallow -> as before
observable.ref -> error, modifiers are separate API
@observable.ref -> as before
@observable.computed
get x() { ...} -> as before
observable.computed(() => ...) -> error, docs even say "This form of computed
is not used very often"
observable.computed.boxed(() => ...) -> `{get(), ...}` as computed() was before
// *very clearly* only do this kind of thing (completely modify the interface
of "x") in the boxed method
boxedObservable(x) -> {get() => x, set(x) => void}
@boxedObservable -> error, no one needs this
// I also think it would be better to have this not be deep observable
// automatically, but I'm not sure.
* Modifiers
modifier.ref() -> as observable.ref() before
modifier.shallow() -> as observable.shallow before, but throw an error if any
primitives or null are passed. what does
observable.shallow("123") mean??
...
To me the proposal seems:
collection()
with default options, but it doesn't play well imo, especially in relation to deepObservable@deepObservable
<=> collection(o, { deep: true })
?Counter proposal:
What about depth
option (probably already discussed)? Depth seems quite self explanatory (?) and universally usable, so we could get rid of ref/shallow/deep/box:
depth: -1
(default) is deep
depth: 0
is for ref or box
depth: 1
is for shallow
depth: n
shouldn't be too hard to support any arbitrary depth (?) alternatively we can treat n>1 as deep
The question is how to specify "depth" (or any option in general), so I would go for:
@observable() // brackets are mandatory
@observable({ depth: 1 })
@computed()
@computed({ equals: () => {} })
observable(o, { depth: 1, name: "name" })
/*
Dunno about extend...
I am convinced that options object should be defined per property same as decorators.
However defining key + value + options in consistent way, without being too verbose is quite a challenge.
So aside of current and a bit magical "descriptor/modifier" solution, there are some less magical, but more verbose alternatives:
*/
// Object.defineProperty approach
defineProp(o, key, {
value: val,
depth: 1,
})
defineProps(o, {
key: {
value: val,
depth: 1
}
})
// Helper for applying decorators
decorate(o, {
key1: observable(), // value is taken from "o.key1"
key2: observable({ depth: 1 }), // value is taken from "o.key2"
})
// we could allow "value/initialValue" option
EDIT: btw I also don't have much of a problem with current API
Whats wrong with the current API? Its pretty good.
My paint of the bikeshed:
@observable.ref // only the reference
@observable.collection // converts refs + one level items
@observable // automatically converts assignments to deep observable
observable.(map|set|array|etc) // "shallow" collections (don't auto-convert contents)
observable(collection) // automatically converts objects/collection/subcollections, deeply
additionally, any existing tagged observables would stop deep conversion, since the consumed object knows better what should and shouldn't be (deeply) observable.
Hi all!
Time to start thinking about the next major of MobX. These are some of the ideas I have around them. Global goal:
Leverage modern features in evergreen browsers to address current quirks in the MobX api
Quirks being:
Tools to address the quirks: levering proxies #776 and native map implementations #800
Breaking changes
observable(object)
will now make all properties (including future ones) observable. To limit / specify the set of observable properties one will have to useextendObservable
isArrayLike
will be deprecatedArray.move
will be deprecatedAlso fix #940 if not done before
Tasks:
extras
namespace for better tree shaking