
Re-Frame:  a Reagent Framework for Writing SPAs, in ClojureScript - jdnier
https://github.com/Day8/re-frame
======
sandbags
Re-frame provides a very sane model for producing even complex applications.
The clear separation of responsibilities and the simple data-flow (esp. once
effects & co-effects come into the picture) are a powerful combination. While
I have wryly observed its hegemony, good taste forbears any significant use of
Javascript. ClojureScript + Re-frame make browser based development fun.

~~~
lambdadmitry
Completely agree, explicit effects and coeffects made it sooo much clearer.
The only downside I can think of is that the names make the idea seem more
complex and can remind of Haskell, but in reality it's very simple and useful
abstraction.

~~~
sandbags
Yes it took a bit of grokking, too much for something that is so simplifying.
But overall a minor blemish I think we will both agree :)

------
hkjgkjy
The Readme is worth reading even if you are not into Lisp languages - just
because it is good entertainment.

~~~
lgessler
One of my favorite snippets:

>You know what's good for you, and you know what's right. But it doesn't
matter - the wickedness of the temptation is too much.

>The JS world is brimming with shiny component baubles: D3, Google Maps,
Chosen, etc.

>But they are salaciously stateful and mutative. And, you, raised in a pure,
functional home, with caring, immutable parents, know they are wrong.

It feels like there's a bit of a culture in the Clojure community of making
what might have been dry documentation whimsical and fun.

~~~
_vya7
I think it's just a few isolated projects. The only ones that come to mind are
this one and NightCode.

------
arms
The last time I wrote any ClojureScript was over a year and a half ago. I
played around with Reagent a bit and remember really liking it. I never used
it for any serious projects or in anger though - how is the tooling and
debugging experience? I would love to use ClojureScript for my front end work
(since I always end up using React + ImmutableJS anyways) but developer
ergonomics are really important to me.

~~~
xiaoma
Wouldn't JavaScript make you angrier anyway?

~~~
JBiserkov
It probably would. Yet

>to "use something in anger" is a phrase, meaning to use something "for real"
\- in production, etc. rather than just to try it out.

~~~
xiaoma
That's weird, but I believe I remember seeing some DHH writings talking about
_coding in anger_ around the time he was defending cursing and sexually
suggestive mostly-nude slides at Ruby confs[1]. I blew the phrase off as as a
DHH-ism, thinking maybe he believed in trying to remain angry while coding or
something crazy like that. Thanks for explaining the term!

1) [http://david.heinemeierhansson.com/posts/39-im-an-r-rated-
in...](http://david.heinemeierhansson.com/posts/39-im-an-r-rated-individual)

~~~
dkersten
I don't know what DHH meant, but the idiom _" in anger"_ is used to mean "in
seriousness", "for real" or "properly". Whether or not DHH meant the idiom, I
do not know. But its likely.

For example: "I've been tinkering with emacs, but I've yet to use it in
anger."

------
tharibo
I love the README.md's style of writing. It _tells_ a story, and you're bound
to read it.

------
jraines
I love this README, not least because it provides some essential missing
documentation for Reagent (the different component "forms").

That said, I would extend the currently en vogue advice re: React/Redux --
don't reach for Redux by default if it's your first go-round -- here.

We have an app in production which at this point is fair to call medium-sized,
and have yet had no real pain from using plain Reagent (we do keep all state
modifying fns in their own namespace, but basically we just bang on the state
atom and it Just Works)

------
dkersten
Its also worth noting that you can use re-frame with react-native to write
apps with the re-natal project: [https://github.com/drapanjanas/re-
natal](https://github.com/drapanjanas/re-natal)

------
juliangamble
Re-Frame is a fantastic way to do ClojureScript apps.

------
bsaul
I just read the readme, but couldn't understand what the differences are with
react ( except for the language of course). To me they are both running a
single render loop to update and render views from a global state, with some
kind of dom diffing algorithm in the end.

It's not a criticism, and I'm not a react programmer btw, just curious.

~~~
dkersten
React is a rendering library. That is, you create a tree of widgets
(components in react lingo) and feed them data. React then manages the
rendering (turning it into the DOM) for you whenever this data is changed. It
does it in a generally efficient way.

Re-frame is a flux-like, elm-like uni-directional data flow framework that
uses React as its rendering component. What re-frame gives you is a message
bus to which you can dispatch messages from DOM events (eg user clicks button
and you dispatch a user-defined message), a handler registration system which
allows you to register functions to process messages[1], and a subscription
system which allows you to "subscribe" to some view over your applications
state in a way that if this view changes, your react components get fed new
data and get rerendered (if necessary). Re-frame also has mechanisms to
facilitate effectual handlers (that is, handlers which effect the outside
world rather than being a pure function of (app state, message)->new app
state; like normal handlers are).

That is, react does rendering, re-frame uses react and is a complete
application framework that makes it easier to build large complex applications
by allowing you to split your application into smaller (mostly pure-
functional) pieces that communicate through the messaging system.

[1] Message handlers take in the message and the current application state and
return a new version of the application state. That is, they are pure
functions that move the application to its next state. Handlers are quite
powerful and support "interceptors" (decorators/middleware for messages
basically) and there are effect and coeffect handlers for managing side-
effects (like dispatching new messages in a feedback loop, or talking to a
server, for example).

~~~
snippy
Thank you for your great explanation. I've read the documentation of re-frame,
but I still can't figure out how it deals with reusable components and
hierarchies.

Let's say I want to write a reusable datepicker component which sends an event
like [:date [2017 1 16]] when the user clicks on that date. How can it send it
to the calling component? The re-frame pub/sub message bus seems to be global,
but what if I want to have several instances of the same component on the
page?

The only solution I can come up with is to parameterize the component on
instantiation, so that if I have a "person" component that uses the datepicker
to set the day of birth of the person, the date-picker would be parameterized
so that it would emit a global event such as [:set-person-day-of-birth
<person-id> [2017 1 16]]. Is this how re-frame approaches hierarchies?

~~~
phrygian
I would say you don't. I think about it this way: use re-frame to write
applications, but components must be self contained and have no knowledge of
reframe. To do what you asked, I'll pass a function to the component. The
function can then make the context-aware reframe call. That way all your
component needs to do is to call the passed in function.

~~~
dkersten
It depends on what you mean by component. Reagent components (ie UI widgets),
I agree. Components should be self-contained and as re-frame agnostic as
possible. So instead of subscribing to the data they want, they could take in
a ratom as an argument (because the subscribe function returns one anyway).

But if the component is larger (that is, not just the view, but also the
handlers and subscriptions -- I'd probably call it something else, a service
maybe...) then its a bit less simple because not just the view, but also the
handlers and subscriptions need to be aware of the "instance" they are
running. There's no well defined re-frame solution for this yet.

My favourite solution right now is to have each instance have its own ID as
explained here: [https://github.com/Day8/re-
frame/issues/264#issuecomment-260...](https://github.com/Day8/re-
frame/issues/264#issuecomment-260273428)

That is, by convention, subscriptions are always [query-name instance-id
<other optional data>] and messages are always [message-type instance-id
<other optional data>] by convention. This way works quite well, but has the
downside that it is by convention and there's no guarantee that other code
will do it the same way.

~~~
phrygian
Of course yes. My reply was largely tied to the parent's description of a
date-picker component. But for application level components I'd use event
names that are unique at the application level that conveys the intended
semantics of the event. Everything else becomes an argument to that name,
which pretty much aligns with your notion of instance Id et al although I'd be
less rigid about the particular structure of the arguments.

~~~
dkersten
_although I 'd be less rigid about the particular structure of the arguments._

My reasoning was for conpatibility and consistency. If everyone makes up their
own argument structure, it becomes very difficult to maintain and puts the
onus on the developers to remember which components use which structure. I'm
not really asking for much beyond standardising that the first argument of an
instanced event of subscription query is the instance id.

