5 ms·
Local component state is the new two-way data binding. Three years ago, two-way data binding was the gold standard for niceness. Then React came out, and there
by rtfeldman 11y ago
Local component state is the new two-way data binding.
Three years ago, two-way data binding was the gold standard for niceness. Then React came out, and there was buzz around unidirectional data flow, and a lot of (understandable!) skepticism came with it.
If you listen to people who have spent a lot of time with two-way data binding and unidirectional data flow, what you hear are a lot of unidirectional data flow converts and not a lot of people saying "yeah it wasn't awesome so I went back to two-way data binding."
We're watching the same thing play out with local component state versus a single state atom architectures like The Elm Architecture, Redux, etc. As with the React transition, there is understandable skepticism around new things claiming to be nice, but the writing is on the wall.
If you listen to people who have spent a lot of time with both systems, what you hear are a lot of single state atom converts and not a lot of people saying "yeah it wasn't awesome so I went back to local component state."
- boubiyeah 11y agoDon't know, I never liked two-way bindings :) <MuseumTech>Adobe Flex added those at some point but it was a complete downgrade from the simpler one way bindings + events.</MuseumTech> A central state atom has pros (debug tooling and the fabled undo for free being the main ones?) and cons. The cons affects me more than the pros. Clojure's Om and React+redux maintain a central atom but still allow for local state in a pinch. I appreciate your comment but I wish it was a bit more constructive; Why do you think a central state atom is so much better ? How can one write ready-to-use smart components with central state ? (e.g ReactTransitionGroup)
- rtfeldman 11y agoHere's a long-form answer to both questions. :) https://www.safaribooksonline.com/blog/2015/10/29/react-local-component-state/ https://www.safaribooksonline.com/blog/2015/10/29/react-loca...
- boubiyeah 11y agoFine article... But all that it tells me from my experience is that it's a good thing to put 80-90% of the app state in a central atom :p A good practice or rule of thumb is just that, it shouldn't always be the only way to do things.
- rtfeldman 11y agoFlexibility is a fine rule of thumb, but opening the door in those 10% of cases costs you things like time travel. Quite a price tag! :)
- ablesearcher 11y ago@rtfeldman -- I think your response is a bit disingenuous since only yesterday you wrote, in response to a question about cursor state, this: "I wouldn't maintain cursor state in the model; I'd just implement the port like this: http://stackoverflow.com/a/14508837/2334666 http://stackoverflow.com/a/14508837/2334666 In other words, you never use the value attribute on the input; rather, you give it a unique key and don't touch it directly. Whenever you want to change its value, just send the desired new value to that port and let the JS snippet do the "stash cursor position, set the new value, restore cursor position" bit. If you need to do this for multiple elements, send a DOM query string to the port and call document.querySelectorAll (or the like) with it to apply the logic to the correct element." (See https://groups.google.com/forum/#!topic/elm-discuss/I2JleY8bD7c https://groups.google.com/forum/#!topic/elm-discuss/I2JleY8b...) Clearly, you don't even believe that all component local state belongs in the atom. And kicking the issue to JS-land is just hiding the problem. Almost everything should be unidirectional, but @boubiyeah has a valid point. Not everything belongs in a single state atom. (I say this having written a 4000 LOC Elm app, which I'm porting Clojurescript/Re-frame due to precisely this issue.) Even Haskell uses mutable references for this stuff.
- vilterp 11y agoMaybe the answer is for elm-html to put a cursor-state attribute on textual input elements, and have event handlers for selection change? Then you can have the cursor state in your atom if you need it without ports....
- sgrove 11y agoThis is what I expected would already be setup - it'd be a pain to deal with cross-browser stuff when implementing it, but it'd be a dream for app developers (me).
- ablesearcher 11y agoThat might solve the cursor issue, but it's a bigger issue than cursor state. The real issue is that Elm doesn't treat its programmers like grown-ups. That sounds harsh, so let me explain . . . I've drank enough of the Haskell Kool-Aid to realize that, despite the surface discourse, Haskell is not about religious devotion to purity and lazy-evaluation. It's about managing side-effects, and being honest about them in your type signatures. Yes, Haskell allows functional purity but its real genius lies in how well it helps you manage state. (I did an imperative Algorithms course completely in Haskell, and the language really shines. Mutable unboxed arrays, mutable atomic references . . . it's all there when you really need it.) Unfortunately, the folks driving Elm development take a paternalistic tack. (If someone seeks to argue this point, it's not hard to come up with many, many examples from the Elm mailing lists.) Here's a few examples: - Elm shouldn't have type-classes because, allegedly, they are too hard for JS-folks to understand. (https://groups.google.com/forum/#!searchin/elm-discuss/type$20classes/elm-discuss/oyrODCgYmQI/dfkIdosLHRQJ https://groups.google.com/forum/#!searchin/elm-discuss/type$...) - Elm doesn't publish how you are supposed to write native modules (you must discern it from the code and it's subject to change without notice), because Elm's author thinks you can't be trusted to use FFI wisely. (https://groups.google.com/forum/#!searchin/elm-discuss/native$20modules/elm-discuss/jUnFVY8tg7Q/cr5lgpfgK10J https://groups.google.com/forum/#!searchin/elm-discuss/nativ... and the can was kicked here: https://groups.google.com/forum/#!searchin/elm-dev/native/elm-dev/R4WOz9O3mfI/wKNPjKOrBQAJ https://groups.google.com/forum/#!searchin/elm-dev/native/el...) And, no, Elm's ports are not the equivalent of FFI. - In the most recent release, operators were removed because synonyms for map (<~) and apply (~) are allegedly to hard understand. - Appartently, you shouldn't even mention Haskell as a resource for learning Elm. (https://groups.google.com/forum/#!topic/elm-discuss/OlzLOPixsYg https://groups.google.com/forum/#!topic/elm-discuss/OlzLOPix...) I think it's healthy for programming languages to have a point of view; that is, languages should lead you in a direction. (Clojure does a great job at this.) Yet, ultimately, a language shouldn't censor its programmers. Upshot: Component local state should be an option in Elm when you really need it.
- nwienert 11y agoActually, you do see a lot of questions and problems with the single state atom. In fact, I'd argue it's inherently a side step towards a future that has the best of both worlds: encapsulated state within components, but backed by some global state store invisibly. This is exactly what Relay is by the way. You component asks for state, and gets it from a server. The fact that it comes through props is actually just a downgrade because it means you must now treat it as some special thing, and not variables. In the ideal world, we can write simple components that fetch state from wherever (remote, local, global). They store that state into themselves, and it "just works". They can write back that state just like how they write variables. And all of this "local" state would really be backed into a global state store invisibly. Local state - Pros: easy to reason about, easy to use. Cons: trapped in one place, inflexible. Global state - Pros: can be backed in various ways, easier to share. Cons: Hard to use, harder to reason about. Local state backed to global store - Has all the pros and none of the cons. Unfortunately doesn't exist yet today.
- lijnen 11y agohttps://github.com/tonsky/datascript https://github.com/tonsky/datascript
- mweststrate 11y agoWe use both; local component state as long as nobody else (might) be interested (this usually the case for generic components that are not application specific, such as page controls, checkboxes etc). But as soon as state starts to creep upward in the component tree, we move it directly to global state and store it in observable data structures (using mobservable) so that any component interested can use the data in whatever way it was delivered (through props, global state, closures, etc) and (un)subscribe automatically.
- christianalfoni 11y agoHi there, I do not quite agree with this. Though I acknowledge your sentiments :-) 1. Global state is easier to reason about. If you have a single state store expressed as a single object you only have to read one file to understand the complete state of your application. If you let local state express the state and the global state is invisible you have to look into all these local state files and compose the complete state in your head 2. When you define it as local state you risk conflicting with some state set in a different component 3. You still have to change state. If you define your state in your components you will also have to include all the state changing logic inside the component. Your components will become very hard to reason about. And what if two components uses the same state and both of them needs to update the state? You will need to put the same logic into two different components 4. You could say Relay fixes this, but Relay just handles one thing and that is state related to the server. We build applications that does a lot more than talking to the server. Changing the state of your application is a huge problem space and though Relay is cool technology I can not imagine anyone expressing and changing all their state using Relay. So you need some other concept(s) to change all the other state and multiple concepts for doing the same thing is harder to reason about Personally I think local state is a bad idea and currently I also think Relay is too limited. When I jump into an application I need to reason about what state it handles. With a global state store I can do that. Then I need to know how that state can be changed. Ideally that should be one concept, but we usually have lots of concepts for changing state. Then I want to see how the UI is expressed. Components are great for that, except when they are filled up with state definitions and state changing logic. So from my perspective I am also trying to contribute with a solution :-) www.christianalfoni.com/cerebral
- ryanflorence 11y agoI went back to component state.