in Response to another recent thread:
@SkinnyGeek1010 had the following astute observation about the direction of React:
I’ve been doing a lot of research on Elm and ClojureScript and it seems to me that components don’t even need to be “stateful”. The framework (React) can handle all the side-effects of binding everything together and passing your functions everything you need–just like side effects is addressed in Elm with monads or (monadic-like solutions) and like Redux seems to address with “middleware”. @SkinnyGeek1010 brought up an example of a “stateful function/module” and it looked like this:
// react stateful module
function handleClick(props, state, event) {
if (event.button === 1) {
return { count: 0 };
}
if (props.onClick) {
props.onClick();
}
// state gets returned instead of using this.setState
return { count: state ? state.count + 1 : 0 };
}
export function componentDidMount(props, state) {
console.log('mounted');
}
export function render(props, state) {
return (
<div>
Clicked {state.count} times
<button onClick={this(handleClick)} style={{ width: props.width }} />
</div>
);
}
And what I’m saying is we could even remove this
from handleClick
making it stateless:
export function render(props, state) {
return (
<div>
Clicked {state.count} times
<button onClick={handleClick} style={{ width: props.width }} />
</div>
);
}
The platform passes in state
instead and ideally gets it from a single source of truth atom, thereby removing the requirement that components maintain any of their own state. Or, simply passes it in as props
just as Redux does via “higher order components”–and for event handlers passes in the global state atom in addition to the props of the corresponding component.
A true purely functional platform is possible, at least from the standpoint of the application developer. That said, even in utmost of “pure” functional languages, the canonical example being Haskell and Elm, the word “pure” isn’t quite, well, “pure.” Rather, based on my research, they just go to great lengths to get you to address unavoidable “side-effects” THE RIGHT WAY. Again, Redux does that with “middleware,” clojurescript has its own set of guarantees (though a lot looser than Elm), etc. The way I’ve come to look at React as one big side-effect management solution for a “state stream.” Unlike Elm or Cycle it doesn’t address streams/observables for things like mouse clicks, keyboard interactions, etc, async requests (and basically anything that can be represented as a stream under a unified interface). That’s where React looks more like an “FP” approach rather than a true “FRP” approach. …So back to my point here: basically if React develops a broader yet unified way of dealing with side-effects similar to how Redux has started with “middleware,” I see no reason for components to maintain their own state; in addition, i see various “hooks” (aka “middleware”) being provided for us to hook into side effects, e.g. subscribing to data. ClojureScript’s Re-Frame library, has you calling a subscribe
function within your render
function (although it’s not called render
, it’s called whatever the name of the component is since your component is now always one function) and then returning a function that has your render code. Eg:
(defn MyComponent ;; outer, setup function, called once
[]
(let [name-ratom (subscribe [:name-query])] ;; <---- subscribing happens here
(fn [] ;; the inner, render function, potentially called many times.
[:div "Hello" @name-ratom])))
In this case subscribe
is a side effect. But, it’s part of a system that “pushes to the edges” and boxes in side effects, while leaving your application code testable, and in addition leaving your side-effect monadic middleware–or whatever you wanna call it–also testable. The idea being: well, if i can push all the side effect to the edges, that stuff needs to be testable and functional as well. I’m still researching exactly how that’s addressed. But it’s looking like languages like Haskell have solutions built in for things like IO, whereas javascript will likely reach one area where you’re gonna have to trust the underlying library to have boxed in its side effects and made them 100% leakless. Like, in Redux, we have to trust that middleware that deals with async is rock solid, but there has to be some point in middleware libraries where the creator has to depart from a pure functional approach and just rely on whatever side-effects he/she’s utilizing behaving correctly 100% of the time. I digress…
Back to the idea of both stateless react functions: if we move in the direction of what’s happening with Om Next and Re-Frame in ClojureScript we can just 100% rely on a separate stateful atom (or ratom in Re-Frame). That would mean the state passed in isn’t specific to the component, it’s from the single source of truth atom, perhaps filtered to just the portion of the atom relevant/subscribed_to by the component. I love how Redux enhanced the Flux pattern to wrap components in higher order components, thereby allowing the passing in of what was previously “state” as props. That’s one way to never have to see the word “state” in your component.
One thing that’s going on which is fantastic about Om Next is that they have combined Redux and Relay into one essentially opinionated solution. The idea being you’re using a simplified form of Relay, but you can configure multiple data sources, e.g. a server side one (which is the only one Relay currently supports) which you can use for “Domain State” and a client one (i.e. like Redux) which you can use for “UI State”. That way you don’t have to learn and utilize 2 separate interfaces. It’s “reducer powered” and therefore supports time traveling. It’s using the Datomic database, and therefore inherently subscribeable (it comes with Subscriptions out the box, which Relay doesn’t support yet). So it’s solving all these things under a more unified opinionated framework. Plus, it’s already functional! I assume the React world will eventually get there, like in 2 years, but in Clojurescript you already have the sort of opinionated (and therefore simpler because of less choices) that Meteor is today.
My overall point is the future is already here. It’s in ClojureScript. I’m leaving out Elm because Elm isn’t full stack. This is particularly important news to Meteor developers. ClojureScript (utilizing Om Next) is presenting a full stack–opinionated–solution much like Meteor, but for 2016! In addition, Om Next is the “future React” but Today! Well, actually, Re-Frame is the future React in that you are doing things like the subscribe
example above via sets of purely composed functions; and Om Next is the future react in that it offers a Relay + Redux hybrid, while also offering subscriptions, caching, and an interface that is actually usable (“bare metal” Relay takes lots of boilerplate work). The one caveat–or rather"requirement" if you wanna look at it that way–is you gotta use the Datomic database, which is developed by the same guy (Rich Hickey) and company (Cognitect) behind Clojure and Clojurescript and Om. But that said Datomic very much is the subscribeable stream-based database (for today) that is being talked about in the famous “Turning the Database inside out” talk here: https://www.youtube.com/watch?v=fU9hR3kiOK0 …I’m not sure where it falls short, but at the end someone asks how Datomic compares, and the presenter didn’t have much to say regarding how Datomic falls short. I gotta research it more, but it’s basically looking like Datomic offers native built-in support for what Meteor hacks together with Oplog, which we all know doesn’t scale.
…Anyway, I just wanted to chime in somewhere as I’ve been doing a lot of research on all this–basically learning Elm and ClojureScript–and haven’t fully formed an opinion yet. Look forward to a longer more formal piece when I do. On a side note: Tracker is basically looking “out” as a solution. Whereas before, I was trying to “save tracker” or at least give it one final shot. It’s just really looking like the automatic approach of making functions re-run themselves is super dangerous, and the pro approach is a full system designed to run your code in a “cycle” (like Elm and Cycle), passing actual arguments of things that represent changing values over time. Tracker is nice in that in “ad hoc” way it lets you make any function re-run itself just by using essentially an “observable” within its function body. But when it comes to real apps, you need a system that makes such “signals” or streams/observables" first class citizens. What’s great about Elm is that it addresses this all the way down to the language level. It’s a language designed for streams. Cycle gets the job done, but it’s messier. ClojureScript and React is FP with some hooks that address the side-effects of having streams run through it. ClojureScript though not designed for FRP to begin with like Elm is can look pretty damn close thanks to its built-in Macro features. ClojureScript, like Javascript, of course has various ways to deal with streams, specifically what Clojure calls “Channels.” That why I’m leaning towards ClojureScript currently as the best overall solution. That’s not to mention it makes better use of the NPM ecosystem than Elm does, provides general interoperability with javascript, provides the same language on the server, and has a “native” database which you can interface with in the same language!
If you wanna take the plunge on ClojureScript, read these:
https://funcool.github.io/clojurescript-unraveled
http://www.braveclojure.com/
both free online.
Watch every David Nolen talk on Youtube. He’s the creator of Om and works at Rich Hickey’s Cognitect company (which, again, is behind Clojure/ClojureScript/Datomic). Here’s a good Om Next one from July you should start with:
Keep in Mind that Om Next is based on React (yes, you can render to React Native)–so that’s why it’s super relevant to React developers or Meteor developers who are thinking of switching (i.e. you may just wanna just switch your whole toolset, and get the whole upgrade job done [of your toolset] in one fell swoop).
Here’s where you can learn about Om Next (it doesnt seem fully out yet):
Here’s David Nolen’s blog:
And here’s Re Frame:
Re-Frame i seriously recommend checking out. If this had what David Nolen is doing to bring Relay-style features to Om Next, I’d go with Reframe over Om Next. Om Next tries to look more like the React of today–it basically has full on components. I.e. it’s less functional than Re Frame. Re Frame is that pure functional approach that Redux is dragging React towards. It’s it, but now–just in another language. My guess is Om Next wants to look more like the class-based React of today in order to inspire Javascript developers to give it a try. That has to be the marketing move there. That said, that may be exactly what you want. Me personally, if I had to make a decision (which im still in the process of determining) I’m gonna pick the one that supports the Relay-style features. Based on my current research only Om Next offers that. But I assume Re-Frame will copy those features in the near future if they aren’t already. When Re-Frame gets them, I’d go for Re-Frame, given its the purer functional approach.
The 3rd and final ClojureScript framework worth checking out is https://hoplon.io . This perhaps is the one most like Meteor in that it seems to be doing the “Transparent Reactive Programming” with “spreadsheet”-like reactivity, i.e. like Tracker and Mobservables. Hoplon’s Tracker is called “Javelin” and has a concept of a “cell,” as in a spreadsheet cell. Hoplon also has some great isomorphic features for making your permitted server code accessible on the client. Similar to Meteor.Methods
and sharing code between both the client and server.
In short, there’s a lot going on in ClojureScript worth checking out. I wanted to present it to you guys–because there’s so much information out these days it’s near impossible to pin down what’s what. Sorry, if this piece wasn’t super well written and is a bit informal. I just wanted to get something out while it’s on the top of my head and relevant to you guys as the new year has started already. Look forward to a formal and thorough Medium piece in the near future where I really dissect and break things down so you don’t have to spend the weeks of research it’s taking me. I’m essentially trying to synthesize and reconcile the strengths and weaknesses of Elm, ClojureScript (and its frameworks), Cycle.js, React, FRP, FP, and the Meteor/Blaze/Tracker world we came from (while basically having to learn multiple languages along the way) in order to determine the best path(s) going forward. Happy New Year Meteor World!!