This is the main shift. It's very similar to how imperative programming is done in Java vs Haskell.
This is the main shift. It's very similar to how imperative programming is done in Java vs Haskell.
Furthermore, the input-process-output model can hardly warrant being called "functional" in of itself, unless you really want to overload the term.
The React way of independent handlers that trigger events which incrementally calculate state and update views, is, in fact, quite similar to how Smalltalk UI paradigms work, right down to the installation of an event handler resembling a message send operation.
If you don't believe me, check out the Morphic framework that Self uses to implement its environment UI. The similarities are striking: http://handbook.selflanguage.org/current/morphic.html
input-process-output is how pure functional languages (such as Haskell) deal with imperative coding. You push the imperative part to the top of the call stack and try to keep the rest of the computation pure.
JavaScript inherited quite a bit from Smalltalk, so you will find similarities like these in JS in general.
Flux supplements the standard React bubbling of events up the chain of components with a simpler, singular flow, making it even more functional.
In fact, you're equivocating the entire management and abstraction of mutable state as an inherently "functional" thing, which it is not. OO is just as much capable of factoring state as a virtual resource that you explicitly make transitions to and from and transparently or visibly share increments across object boundaries, as this is exactly what e.g. Self does with Morphic, right down to the same event handler structure. Just because one is a lambda and the other is called a method doesn't make a huge difference.
I'm saying that just about all of React's insights were done previously almost verbatim in thoroughly object-oriented environments. That some FP evangelists have a kneejerk hatred for it doesn't mean the mental gymnastics for insisting one over the other is necessary. They can be complementary.
I would also never claim that React invented any of this. It just popularized this more declarative approach for building Web UIs
Additionally I'm not sure where you're getting this "JS can't be functional" opinion from. Just because it doesn't give you compile-time or runtime guarantees, or because the syntax may be more clunky, doesn't mean you can't get these benefits by convention.
I never said this. I was talking more about the React architecture, specifically.
Though in general there is this phenomenon to grasp at any similarities and start espousing how functional a particular language/framework/library is, as if for street cred.
That's nonsense. There have been data binding frameworks used for well over a decade in JS development - I know I wrote one in the early 2000s. You can't write a decently sized app in JS without developing something like data binding, unless you love busywork and bugs, or have zero prior experience of what came before in GUI frameworks.
Data binding is designed exactly to prevent the need to explicitly mutate all the views at every point that the model can change. Instead you write bindings that project the model into the view, and make the model reactive, so that changes to it propagate automatically. It's the same in any decently sized Backbone app - that's why the Collection and Model give you all these events.
What's new in React is the idea of cheaply creating a virtual DOM and extracting a set of diffs from it that can then be applied to the real DOM. I did something vaguely similar, again in the early 2000s, but the motive then was to reduce the amount of data on the wire (the server had a data-bound model of what was displayed on screen, but only sent diffs back to the client). It's a neat idea and an excellent implementation, but it's not original or groundbreaking.
I'm not grokking the significance of why changing everything and having mutations is bad.
-E.g. use React (or Backbone, Angular, etc.): A real-time document editor, with many interacting components, with lots of real time updating of the UI. Definitely needed a framework like that, and it was great.
-E.g. don't use React, because in these cases it's a total Rube Goldberg machine (extra steps to achieve the exact same outcome): Basic web app with some ajax submissions, adding results to DOM type of stuff. Maybe small html fragments cloned, inserted by jQuery. No extra fancy client interactivity.
^If people claim you should use React for the latter (undoubtedly some will), they are very likely just people who follow trends to follow trends, or maybe don't have a ton of web experience and it's one of the few things they've learned and are sticking to. It's just so unnecessary (not to mention 100kb+ of overhead, & in my experience comes out to about x3 the amount of code). But yeah, absolutely use React if it's anything like the first use case.
I was not making a judgement on the value of the approach, although I personally believe that this paradigm shift has a huge positive impact and is applicable in lots of cases. If I can choose between lots of computation intertwined with state mutation and a declarative approach where the mutation happens on the smallest scale, up the call stack, I will always choose the latter (of course, unless you have to mutate to gain performance).
Yes, if app is planning on being more complex, sure use Angular or Backbone or Ember or React. Otherwise, don't. Your pet projects sure, use it; if my team is billing clients, I've learned from experience, you're screwing them if you're not just using basic jQuery or even raw JavaScript which is a lot better to work with these days. If your reasons are only rooted in your abstract preference of design ideals w/o looking pragmatically at the situations, you're likely doubly screwing them.
Fyi this "paradigm shift" is like 8 years old, React is not disruptive, it's just another variation.
regular old html and jQuery + ajax.
Consider a classic drawing API:
// stem
fill('green')
rect(146, 60, 8, 200)
// flower
fill('red')
circle(120, 30, 50)
// leaves
ellipse(173, 120, 40, 20)
ellipse(123, 130, 40, 20)
Now, imagine we first wrote the code for stem and leaves, than later added the code for the flower (in the reference, copied it from elsewhere). The code has a bug in it - the leaves are red. This is just one example: once you have a "hidden" state, you have to manage it. You always have to be aware of the effects that every line makes on the state and how the state affects the other lines. A "React"-like (simply declarative) API would look more like: stem = filled('green', rect(146, 60, 8, 200))
flower = filled('red', circle(120, 30, 50))
leaves = [
filled('green', ellipse(173, 120, 40, 20))
filled('green', ellipse(123, 130, 40, 20))
]
plant = [stem, flower].concat(leaves)
...
draw(plant)
The code is now referentially transparent, I could replace uses of variables by their values and nothing would change, since the functions have no effects. The effects are pushed to the edge of the code, in this case the call to draw which actually performs the drawing, or when React updates the DOM with the results obtained from a render method.You can (and I do) view the React render as an idempotent projection from state to DOM, otherwise known as a template. React is a very fancy template system. You build your fragments (components) up into views, pass in your data, and render the entire page as if you're rendering it from scratch. It handles or provides hooks for all the situations I mentioned in the previous paragraph and React's internals ensure that it's reasonably performant by default. Having everything conceptually fully render from scratch every change means there's no separate handling for the initial render versus updates to the initial render (e.g. you have an accordion, render it with an ejs template but toggle it open/close by toggling classes). It makes the Backbone model work in a way that's easy to reason about.
A real world example: I've implemented (B2B, not something I can link) a drag and drop layout builder as a contract. The workalike they wanted, which I had also worked on but didn't design, was ~6k lines of node/class manipulation and mousenter/leave hit testing while my React version worked out to be around 600 lines, most of which were generating virtual screen position hitboxes for the various drop zones. Hovering/dropping in a zone changes attributes in a list of JS objects and the visual feedback is handled by the rendering code you'd need to draw the layout anyway plus another 20% for the drop previewing/hovering.
Most savings aren't as dramatic but in general you wind up spending less effort getting your views right. The LoC isn't always that much lower but it's template code instead of manipulation code. There are other benefits like component composition just working, server side rendering, putting all your app state in one place lets you do session recording and time travelling debugging but this post is long enough as is.