6 ms·
Mobx: Simple, scalable state management
- ikido 11y agoI know that a lot of people like to use different kinds of flux libraries for their React apps, with Redux having a lot of traction, but you should definitely look at Mobx. We've introduced it to one of our project 4 months ago and our state management became as simple and easy as it should be with React. No boilerplate subscriptions, no helpers that modify normalized data, no endless re-renders on every state change and very easy to understand concept for new developers. We literally stopped worrying about the state though it took some time to rewrite the app.
- rpedela 11y agoWow, looks really interesting! With Flux/Redux I have control over when and how data is updated, but that is not the case here. What are the performance characteristics? Is there a limit to the number of observables before performance suffers? There is also the question of routing and history. What is the best way to use observables in a single-page app along with routing and history (i.e working back button)?
- ikido 11y agoNo difference in how you handle routing and history in a regular React app, those things are not related. Mobx (and mobx-react) just re-renders your component when data changes. You can check out performance tests here: https://www.mendix.com/tech-blog/making-react-reactive-pursuit-high-performing-easily-maintainable-react-apps/ https://www.mendix.com/tech-blog/making-react-reactive-pursu...
- jesstaa 11y agoPerformance characteristics are that this increases expsense with the size of your data where as just re-rendering increases expense with the size of your UI. It's actually much more common to have lots of data but only render a small amount of it, so re-rendering is generally cheaper. The size and complexity of UIs have a natural limit because of screen size and usability, but the amount of data you use to generate a UI has essentially no natural upper limit. Pete Hunt gave a talk on exactly this almost two years ago. https://www.youtube.com/watch?v=-DX3vJiqxm4 https://www.youtube.com/watch?v=-DX3vJiqxm4
- ikido 11y agoThat's a good point, but in Redux you subscribe to all changes in single state tree where all data lives. That means that every update of data (which has no upper limit) will cause your UI to re-render. Sure, you can implement shouldComponentUpdate, but still it will be called on every state update, plus you do can do exactly the same with mobx. The difference is that with mobx you subscribe to changes of certain data, and it happens automatically.
- jameslk 11y agoI've used both Redux and Mobx in two different large-scale consumer-facing apps. Mobx has proven to be a lot easier to grasp and much more flexible to different scenarios. I had to use a lot of hacks to get Redux to play nicely with different libraries since it treats JavaScript as an immutable world[0] and Mobx has greatly simplified this issue by providing tools to handle situations where objects may mutate[1][2]. 0. http://stackoverflow.com/questions/32352982/how-to-put-methods-onto-the-objects-in-redux-state http://stackoverflow.com/questions/32352982/how-to-put-metho... 1. http://mobxjs.github.io/mobx/refguide/modifiers.html http://mobxjs.github.io/mobx/refguide/modifiers.html 2. http://mobxjs.github.io/mobx/refguide/extending.html http://mobxjs.github.io/mobx/refguide/extending.html
- honua 11y agoI found it quite the opposite in that I grasped Redux immediately and felt lost in fog trying to work out using Mobservable
- jameslk 11y agoI spent a lot of time trying to wrap my head around certain features of Redux. For example, all the currying used in various places (especially for middleware) makes it hard to follow what's going on. Indeed, the author points out in the guide on middleware tongue-in-cheek, "If your head boiled from reading the above section, imagine what it was like to write it." Part of my job is to figure things out and explain it to others. When I have a hard time understanding things myself, imagine how it's going to go for explaining it to someone else. On the other hand, Mobx also did take a bit of time to figure out its API, but once it was clear, it was very straight forward how to use it and explaining it to others was also painless. No need for extraneous action-creators/reducers ceremony and no opinionated way of what kind of data I can use, or gotchas when that data is mutated.
- danabramov 11y agoWell, to be fair middleware is a rather advanced feature and most users don’t ever need to write one. Action creators are also a mere convention and are not essential to Redux. You can dispatch action objects inline if you prefer. Reducers do add some ceremony, and I wrote up a little on the reasons here: https://news.ycombinator.com/item?id=11187727 https://news.ycombinator.com/item?id=11187727 Glad you found something you like though! No solution is perfect, and it’s all about the tradeoffs you care about.
- jarpineh 11y agoI took a look. This seems intriguing because it doesn't bring the whole RxJS with it to make observables work. Though I'm a bit baffled by the developer's statements about immutability of values in his SurviveJS interview [1]: "With mutable data structures, it is trivial to guarantee that there is only one version of a certain domain object in memory." I'd like to know how this mutable values can be tracked while immutable values can just equality check. I'm currently learning ClojureScript with few simple projects, and its immutability both pleases me and drives me crazy. Though I can agree on his point that Flux (and Redux) do take over your application. I'd definitely like to use something else with my next React project if possible, and Mobx looks it could fit the bill. Also, SurviveJS is a good React and Webpack book that's continuously expanded and adapted to use different libraries (like for Redux and Mobx). You should buy it! [1] http://survivejs.com/blog/mobservable-interview/ http://survivejs.com/blog/mobservable-interview/
- ikido 11y agoThe concept of tracking data is actually quite simple — when you define some object property as observable it is replaced with a getter & setter that invoke a callback when you get/set that property. Then you can bind a function that will be called when data is changed (via setter). You can also wrap some code into special autorun function, that will track what observable data was accessed, and when that data changes, that code will be called again. But wait, there's more =) It works with arrays, objects and other types, check out the docs!
- jarpineh 11y agoThank you. I like the idea of autorun function. Perhaps it could do logging or gathering debug information without having to touch so many places like Redux seems to require.
- mweststrate 11y ago"With mutable data structures, it is trivial to guarantee that there is only one version of a certain domain object in memory." That statement refers to the fact that you loose (automatic) referential integrity when you start using Immutable data. Take the following scenario: you have an app with Users and Tasks. Tasks can be assigned to users. When you express this using immutable data you have two problems. The first one is linking tasks to users. If you would link Task1 to Person1 and after that change the name of Person1, you would get a new person, Person1v2. However Task1 would still refer to the old, unmodified Person1, so then you have suddenly two versions of the same person in memory. A fresh and a stale one. In other words, you lost referential integrity. Now the usual way to fix is, is to not use real references, but to normalize data and store only a key to the person. The effect of this is that you have to always lookup the person related to Task1 again from the state tree. If you have a reference (variable) to that person somewhere, make sure it is short-lived because you won't know if you are still referring to the correct one. The second problem is that when you have correctly normalized your data and always do fresh lookups, you will still not know _when_ to make these lookups. If you have a TaskView that renders the name of the related Person, and the related person changes, the TaskView will not detect this automatically. The related person is not even a prop of the TaskView component so pushing a new state tree through your app won't repaint the TaskView if you are using PureRenderMixin (which is usually the purpose of using immutable state trees in the first place). For that issue there is a solution as well; you can introduce selectors (or lenses) that query the state tree to detect if the relevant person is changed. So now we already have three new concepts (no refs, normalization, lookups, selectors) to solve a problem that mutable data doesn't have in the first place. By using mutable data and observing it using MobX these problems are solved (imho) more elegantly: references are never stale because if you would modify Person1, Task1 would still refer to the 'latest' person1, because it is still the same object. Secondly, because it is the same object, fine grained object observers can be established automatically for you, making sure the TaskView gets updated as soon as something relevant changes. This means that you have less concepts to learn and maintain (no copy-on-write, no need to assign a unique key to everything, no data normalization, no lookups, no selectors to make sure your views are always in sync with the state). That saves a significant amount of boring yet error prone work when your application's state model becomes more complex than the average Todo app. So that is the long story behind that short comment. I hope it clarifies the statement!
- gcb0 11y agoseems like a very convoluted and inefficient way to have getter and setters without saying those words
- lootsauce 11y agoThere is no way for me to succinctly express how great I think this project is but let me try. IMHO this is the most sophisticated yet simple solution to state management for web apps out there. I have worked on several large Angular and React apps and worked with several flux frameworks. I have also written my own Flux like architecture seeking to improve and simplify state management by reducing boilerplate and increasing performance, so I have thought about all the issues involved a lot. It is one thing to put together a set of observations like the Flux architecture that makes a lot of sense and simplifies app development. It is entirely another thing, as we have seen in the past couple years, to implement an elegantly simple and clean expression of that. It is deceivingly simple but in my experience even though it seems to have a bit of magic behind it (which I generally dislike) Mobservable now MobX is probably the simplest and ultimate progression of state management for React and other like apps. It is the reason I stopped development on my own state management system. Once I envisioned how to remove even more boilerplate even more odd conventions I came to realize Mobservable achieved it all, and the performance was just as good too. It really deserves the attention of any serious app developer and it's not limited to React either.
- s369610 11y agoNice, looks to me like it covers most of what is proposed in here the Deprecating Observers paper here: http://infoscience.epfl.ch/record/148043/files/DeprecatingObserversTR2010.pdf http://infoscience.epfl.ch/record/148043/files/DeprecatingOb... Slightly different implementation since it uses untracked() instead of .Now to avoid dependency creation and a nice bridge to the regular observable universe (they have autorunAsync) but it would be good to have a reactor that can act as an observable using emit etc and if the observables could be modified with throttle, or buffer etc. Edit: I have been enjoying similar reactiveness using ractivejs but it hasn't managed to split the reactive data from the view logic.