ANN: Cloact, yet another React wrapper for ClojureScript

633 views
Skip to first unread message

Dan Holmsand

unread,
Dec 19, 2013, 9:39:14 AM12/19/13
to clojur...@googlegroups.com
It seems to be quite popular these days to try to fit Facebook's React library into ClojureScript, so I thought I'd have a go as well...

The result is here:

https://github.com/holmsand/cloact

Cloact uses plain cljs functions to define React components, and a Hiccup-y syntax for stringing them together.

Performance seems to be quite good, especially in advanced-compilation-mode. Cloact uses shouldComponentUpdate to avoid any unnecessary rendering, and so avoids the cost of converting from cljs vectors and maps a lot of the time.

Cloact comes with a couple of silly examples:

https://github.com/holmsand/cloact/blob/master/examples/simple/src/simpleexample.cljs

(a fancy clock that even can change color) and

https://github.com/holmsand/cloact/blob/master/examples/todomvc/src/todomvc.cljs

(the obligatory todomvc implementation).

Enjoy,

/dan

David Nolen

unread,
Dec 19, 2013, 10:49:32 AM12/19/13
to clojur...@googlegroups.com
Great to see the growing interest in React :)

It's also worth giving Om a look: http://github.com/swannodette/om. The implementation is very simple - the big idea is that we might as well always re-render from the root. Then the *entire* UI can represented with EDN and is always snapshotable. It's really, really fast.

I've been in touch with the React devs and they seem open to making/accepting patches that make React nicer to use from CLJS.

David



--
Note that posts from new members are moderated - please be patient with your first post.
---
You received this message because you are subscribed to the Google Groups "ClojureScript" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojurescrip...@googlegroups.com.
To post to this group, send email to clojur...@googlegroups.com.
Visit this group at http://groups.google.com/group/clojurescript.

Dan Holmsand

unread,
Dec 19, 2013, 1:01:04 PM12/19/13
to clojur...@googlegroups.com
Yes, React is really great (and it actually seems to fit ClojureScript with its immutable datastructures better than JS...).

/dan

Murtaza Husain

unread,
Jan 13, 2014, 7:02:54 AM1/13/14
to clojur...@googlegroups.com
Hi,

Thanks for cloact, its great !

I was comparing the BMI Calculator from hoplon and cloact, and could see that the hoplon approach was more simpler for one primary reason - their use of FRP (javelin) to tie in the model pieces.

So when a user change occurs, instead of calling change-bmi, the hoplon example simply changes the weight/height. This causes the respective bmi to change, which causes the ui to rerender.

Cloact currently uses an atom to propogate state changes, is it possible to swap it with the javelin piece ?

Thanks,
Murtaza

Dan Holmsand

unread,
Jan 13, 2014, 7:36:34 AM1/13/14
to clojur...@googlegroups.com
Thanks!

If you wanted to, you could simply use two atoms for weight/height, and a simple function calculates the bmi on the fly from them – that would work as in the Hoplon example.

But you probably don't want that :)

With a map in a single atom you get more flexibility. For example: my little demo allows you to change also the bmi parameter, and have the weight change correspondingly, as well as the other way around.

And in general, it probably will be easier to make sure that your data is consistent if you keep state that belongs together, together...

/dan
> You received this message because you are subscribed to a topic in the Google Groups "ClojureScript" group.
> To unsubscribe from this topic, visit https://groups.google.com/d/topic/clojurescript/vdVW1eeLiag/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to clojurescrip...@googlegroups.com.

Bob Hutchison

unread,
Jan 13, 2014, 9:16:06 AM1/13/14
to clojur...@googlegroups.com

On Jan 13, 2014, at 7:36 AM, Dan Holmsand <holm...@gmail.com> wrote:

> And in general, it probably will be easier to make sure that your data is consistent if you keep state that belongs together, together...
>
> /dan

Or you could add refs to Cloact’s repertoire :-)

BTW, Cloact is looking quite nice. I’m going to start converting one of my more complex React projects to Cloact today.

Cheers,
Bob

Dan Holmsand

unread,
Jan 13, 2014, 10:46:49 AM1/13/14
to clojur...@googlegroups.com
I'm not entirely convinced yet that implementing preemptive threads and refs on top of them is a great fit for Cloact's minimalistic goal :)

Thanks,

/dan

Bob Hutchison

unread,
Jan 13, 2014, 12:41:42 PM1/13/14
to clojur...@googlegroups.com

On Jan 13, 2014, at 10:46 AM, Dan Holmsand <holm...@gmail.com> wrote:

> I'm not entirely convinced yet that implementing preemptive threads and refs on top of them is a great fit for Cloact's minimalistic goal :)

No! That’s not quite what I meant, even though it’s what I said! I’m familiar with Clojure but new to ClojureScript and have just (re)realized that refs are not implemented. So, yes, my suggestion is even more ambitious than I thought it was :-)

I’m running in my browser, right now, a function that updates the render state and React is given the opportunity to redraw before the function continues (i.e. it re-renders right after the swap!). This is certainly within the rules. If you have multiple atoms that need to be updated then you’ll potentially see React re-render between each atom update… i.e. there will be React renders where the atom values are uncoordinated/inconsistent (possibly doing silly stuff on the screen, momentarily at least). I can imagine some very crude techniques to prevent this, do you know any good ones (beside putting all state in one atom (which, personally, I had been planning to do anyway))?

Cheers,
Bob

>
> Thanks,
>
> /dan
>
> On 13 jan 2014, at 15:16, Bob Hutchison <hutch...@recursive.ca> wrote:
>
>>
>> On Jan 13, 2014, at 7:36 AM, Dan Holmsand <holm...@gmail.com> wrote:
>>
>>> And in general, it probably will be easier to make sure that your data is consistent if you keep state that belongs together, together...
>>>
>>> /dan
>>
>> Or you could add refs to Cloact’s repertoire :-)
>>
>> BTW, Cloact is looking quite nice. I’m going to start converting one of my more complex React projects to Cloact today.
>>
>> Cheers,
>> Bob
>>
>> --
>> Note that posts from new members are moderated - please be patient with your first post.
>> ---
>> You received this message because you are subscribed to a topic in the Google Groups "ClojureScript" group.
>> To unsubscribe from this topic, visit https://groups.google.com/d/topic/clojurescript/vdVW1eeLiag/unsubscribe.
>> To unsubscribe from this group and all its topics, send an email to clojurescrip...@googlegroups.com.
>> To post to this group, send email to clojur...@googlegroups.com.
>> Visit this group at http://groups.google.com/group/clojurescript.
>
> --
> Note that posts from new members are moderated - please be patient with your first post.
> ---
> You received this message because you are subscribed to the Google Groups "ClojureScript" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to clojurescrip...@googlegroups.com.

Bob Hutchison

unread,
Jan 13, 2014, 1:09:33 PM1/13/14
to clojur...@googlegroups.com
A mailing list for Cloact would be nice.

Bob Hutchison

unread,
Jan 13, 2014, 1:20:59 PM1/13/14
to clojur...@googlegroups.com

How does one output html entities in Cloact? Especially &nbsp; Sorry, this is probably blindingly obvious… but I’m blinded.

Cheers,
Bob

Dan Holmsand

unread,
Jan 13, 2014, 1:25:56 PM1/13/14
to clojur...@googlegroups.com
On 13 jan 2014, at 19:20, Bob Hutchison <hutch...@recursive.ca> wrote:
> How does one output html entities in Cloact? Especially &nbsp; Sorry, this is probably blindingly obvious… but I’m blinded.


One doesn't :)

Go with unicode instead: "\u00A0" i think it is.

/dan

Dan Holmsand

unread,
Jan 13, 2014, 1:39:50 PM1/13/14
to clojur...@googlegroups.com
On 13 jan 2014, at 18:41, Bob Hutchison <hutch...@recursive.ca> wrote:
I’m running in my browser, right now, a function that updates the render state and React is given the opportunity to redraw before the function continues (i.e. it re-renders right after the swap!). This is certainly within the rules. If you have multiple atoms that need to be updated then you’ll potentially see React re-render between each atom update… i.e. there will be React renders where the atom values are uncoordinated/inconsistent (possibly doing silly stuff on the screen, momentarily at least). I can imagine some very crude techniques to prevent this, do you know any good ones (beside putting all state in one atom (which, personally, I had been planning to do anyway))?

Aah, I see. That is a very good question: most of the time you shouldn't see any inconsistent output, since React normally batches updates – but only in React's own event handlers. There are ways around that, but none of them are very attractive...

It would probably be worthwhile to have a way to tell React to do the batching thing outside event handlers as well (sort of like dosync), but I don't think that React exposes enough API for that yet (at least not last time I looked).

File an issue on Github if this turns out to be a real problem :)

/dan

David Nolen

unread,
Jan 13, 2014, 1:44:54 PM1/13/14
to clojur...@googlegroups.com
On Mon, Jan 13, 2014 at 1:39 PM, Dan Holmsand <holm...@gmail.com> wrote:
On 13 jan 2014, at 18:41, Bob Hutchison <hutch...@recursive.ca> wrote:
I’m running in my browser, right now, a function that updates the render state and React is given the opportunity to redraw before the function continues (i.e. it re-renders right after the swap!). This is certainly within the rules. If you have multiple atoms that need to be updated then you’ll potentially see React re-render between each atom update… i.e. there will be React renders where the atom values are uncoordinated/inconsistent (possibly doing silly stuff on the screen, momentarily at least). I can imagine some very crude techniques to prevent this, do you know any good ones (beside putting all state in one atom (which, personally, I had been planning to do anyway))?

Aah, I see. That is a very good question: most of the time you shouldn't see any inconsistent output, since React normally batches updates – but only in React's own event handlers. There are ways around that, but none of them are very attractive...

FWIW, this is something I wanted to solve in Om. Application state updates are *always* batched, rendering always occurs on requestAnimationFrame (where available), and there's some basic enforcement logic around trying to update the app state from event handlers to work around inconsistency.

David 

Dan Holmsand

unread,
Jan 13, 2014, 1:55:13 PM1/13/14
to clojur...@googlegroups.com
On 13 jan 2014, at 19:44, David Nolen <dnolen...@gmail.com> wrote:
Aah, I see. That is a very good question: most of the time you shouldn't see any inconsistent output, since React normally batches updates – but only in React's own event handlers. There are ways around that, but none of them are very attractive...

FWIW, this is something I wanted to solve in Om. Application state updates are *always* batched, rendering always occurs on requestAnimationFrame (where available), and there's some basic enforcement logic around trying to update the app state from event handlers to work around inconsistency.

Yes, it is a tradeoff (as everything in life, it seems). Batching-by-delaying would be doable in Cloact as well I think - but then you can get into all kinds of trouble e.g if you need to do something with the DOM, since it will be out of sync with your data. Still thinking about that one, though.

/dan
Reply all
Reply to author
Forward
0 new messages