ANN: Om, a ClojureScript binding to Facebook's React

1,538 views
Skip to first unread message

David Nolen

unread,
Dec 19, 2013, 2:12:12 PM12/19/13
to clojure, clojur...@googlegroups.com

Thomas Heller

unread,
Dec 19, 2013, 4:25:21 PM12/19/13
to clo...@googlegroups.com, clojur...@googlegroups.com
Hey David,

looks really interesting although I have to be a little critical of your benchmarks. Add a download of 200 todos via xhr and then do the render, you will most certainly lose to other JS Framework out there (especially if you choose EDN over JSON) cause of the extra overhead associated with going from mutable->persistent. I quite like react/om and will certainly play with it although I have some worries concerning deeply nested data, since Clojure isn't exactly performant in that situation. Happy to be proven wrong though.

Anyways, nice work. Curious to see/hear more.

Cheers,
/thomas

PS: Found a Bug: add 2 items, delete the first, double click the last remaining. 

On Thursday, December 19, 2013 8:12:12 PM UTC+1, David Nolen wrote:

Samuel Aaron

unread,
Dec 20, 2013, 7:57:19 AM12/20/13
to clojur...@googlegroups.com, clojure
Hey David,

this looks fab. I'm trying to play with it within a stub project of mine. However, I'm not having much success getting it to compile. This is likely to be some cljs setup issue I'm having (there are so many moving parts!).

Steps taken:

* Download, and build latest cljs (0.0-2127)
* Clone om and link to it from within my cljs-src directory
* Modify project.clj file to look similar to yours
* Run `lein cljsbuild auto` and see the following error:

λ lein cljsbuild once
Compiling ClojureScript.
java.lang.IllegalArgumentException: No implementation of method: :make-reader of protocol: #'clojure.java.io/IOFactory found for class: nil
at clojure.core$_cache_protocol_fn.invoke(core_deftype.clj:541)
at clojure.java.io$fn__8551$G__8546__8558.invoke(io.clj:73)
at clojure.java.io$reader.doInvoke(io.clj:106)
at clojure.lang.RestFn.invoke(RestFn.java:410)
at clojure.lang.AFn.applyToHelper(AFn.java:161)
at clojure.lang.RestFn.applyTo(RestFn.java:132)
at clojure.core$apply.invoke(core.clj:619)

My project.clj is as follows:

(defproject overtext "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.5.1"]
[http-kit "2.1.13"]
[org.clojure/clojurescript "0.0-2127"]]
:plugins [[lein-cljsbuild "1.0.1"]]
:source-paths ["cljs-src" ]
:profiles {:dev {:plugins [[com.cemerick/austin "0.1.3"]]}}
:cljsbuild {
:builds [{:id "dev"
:source-paths ["cljs-src"]
:compiler {
:output-to "resources/web/js/cljs-main.js"

:optimizations :none
:externs ["cljs-src/om/externs/react.js"]}}]})


My project directory structure is:

∴ /Users/sam/scratch/overtext
λ tree .
.
├── LICENSE
├── README.md
├── cljs-src
│ ├── om -> /Users/sam/Development/cljs/om/src/om
│ └── overtext
│ ├── onload.cljs
│ └── ws.cljs
├── doc
│ └── intro.md
├── pom.xml
├── project.clj
├── resources
│ └── web
│ └── static
│ ├── index.html
│ └── js
│ └── cljs-main.js
├── src
│ └── overtext
│ └── core.clj
└── test
└── overtext
└── core_test.clj

12 directories, 11 files


Am I doing anything obviously foolish?

Sam

---
http://sam.aaron.name

On 19 Dec 2013, at 19:12, David Nolen <dnolen...@gmail.com> wrote:

> Enjoy, http://swannodette.github.io/2013/12/17/the-future-of-javascript-mvcs/
>
> 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.

Moritz Ulrich

unread,
Dec 20, 2013, 6:39:25 PM12/20/13
to clojur...@googlegroups.com, clojure

David Nolen writes:

> Enjoy,
> http://swannodette.github.io/2013/12/17/the-future-of-javascript-mvcs/
>
> David

Fantastic work! Om is (even in it's current state) really accessible and
easy to use. The TodoMVC implementation you mentioned in the Readme is a
really nice help when following the React tutorial.

I really look forward to using this library for some private and
(hopefully) work-related projects in the future.


Cheers!

--
Moritz Ulrich

Mikera

unread,
Dec 21, 2013, 6:27:56 AM12/21/13
to clo...@googlegroups.com, clojur...@googlegroups.com
This is brilliant, thanks for sharing David!

It might (finally!) be the tool I've been looking for to resurrect my interest in client-side development :-)

Conrad Barski

unread,
Dec 21, 2013, 10:28:44 PM12/21/13
to clojur...@googlegroups.com, clojure
Two quick questions as I am working through the OM stuff... glad if anyone here has some pointers to point me in the right directions...

1. I seem to be unable to get "lein trampoline cljsbuild repl-listen" to serve up a css file on my own Om project... I have my css located at "[project root]/css/main.css" and then reference it in the html as <link rel="stylesheet" href="css/main.css"> but this just throws a 404 error for main.css when I run my program. I've tried many other variations but nothing seems to work. Javascript, html, and sourcemaps work fine. Anyone have an idea of what I'm doing wrong? How does repl-listen decide where the css lives?

2. In the Om TodoMVC app in the function "handle-new-todo-keydown" there is one ugly line of code that reads:
(set! (.-value new-field) "")

Anyone figure out yet why such a DOM manipulation was necessary in that case?

Nikita Prokopov

unread,
Dec 24, 2013, 6:27:12 AM12/24/13
to clojur...@googlegroups.com, clojure
Hi David,

cool work,

Just wondering, why in todomvc you rely so heavily onto #js literals, and prefer dsl-like syntax (dom/...) instead of some declarative markup like hiccup? Is it because of performance reasons?

Thanks!

David Nolen

unread,
Dec 24, 2013, 9:33:19 AM12/24/13
to clojure
No. I just think Hiccup, not-Hiccup, or something else entirely should be left up to users of the library.

David

Conrad Barski

unread,
Dec 24, 2013, 2:55:19 PM12/24/13
to clojur...@googlegroups.com, clojure
I'm not David, but I'm guessing "performance reasons" is the answer. The React library relies on member functions to render html (React.DOM.div, React.DOM.input, etc) so this maps more efficiently onto a macro-based html rendering solution, as opposed to one based purely on EDN (like hiccup). Note that the approach used by Om is common in the Common Lisp & Scheme worlds (since those languages don't have clean map & vector literals like Clojure, the hiccup approach is more awkward in those languages.)

The #js literals can forwarded directly to the React.js library and are therefore also very efficient.

Conrad Barski

unread,
Dec 24, 2013, 2:56:27 PM12/24/13
to clojur...@googlegroups.com, clojure
(Should have written "DSL-based" not "macro-based"

David Pidcock

unread,
Dec 31, 2013, 12:43:46 AM12/31/13
to clojur...@googlegroups.com, clojure
On Thursday, December 19, 2013 11:12:12 AM UTC-8, David Nolen wrote:
> Enjoy, http://swannodette.github.io/2013/12/17/the-future-of-javascript-mvcs/
>
>
>
> David

I've been playing around with some basics. I'm still a relative n00b when it comes to functional programming, and I've never looked at React before.

Very cool stuff.

I managed to get Om+React to display a list of items that are sorted by a given key, and I have a content-editable span which updates the state of the owner with new value of that key for a given item, and voila! the list item moves to the correct position. (as expected)

Now here's the tricky part...
I want to implement a drag-list, where I can drag-drop items into a new position, and update the key based on the new position. I have that algorithm working in a different project (using goog.DragListGroup) , but React does not like you to manipulate the DOM outside it's knowledge.

I found this :
https://groups.google.com/forum/#!searchin/reactjs/sortable/reactjs/mHfBGI3Qwz4/rXSr-1QUcKwJ

which lead to
http://jsfiddle.net/LQxy7/

Unfortunately, I can't get this to work with Om. I am having trouble navigating the data structures.

How are "props" created/accessed? I followed the TodoMVC example, but that seems to be using "state", which I am given to understand should be kept as high in the hierarchy as possible (per the React recommendations). I tried something like (:value (om/get-props this)) from within IRender, but that doesn't work. Also : (om/get-props this [:items] ) (following the idiom established by get-state.

I'm probably missing something obvious, so I thought I'd pop in here to see if there's someone who can point me in the right direction.


David Nolen

unread,
Dec 31, 2013, 1:02:37 AM12/31/13
to clojure, clojur...@googlegroups.com
From a React dev:

https://www.khanacademy.org/preview/content/items/xfa03b103

I'm sure this can be adapted for Om. I may write up a simpler Om example in the future.

David


--
--

You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com

Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

David Pidcock

unread,
Jan 2, 2014, 7:00:45 PM1/2/14
to clo...@googlegroups.com, clojur...@googlegroups.com
Very nice. Relatively easy to follow.  Basically it's re-implementing the drag-list behaviour  in React.  I had thought to re-use some existing code, provided I could inform React that the DOM was changing. (This is the approach used by the example in the fiddler, albeit with jquery instead of goog.closure as the UI manipulation library)

I'm very interested to see what you do with this, in Om.
This example is complex enough that following along would most likely fill in the conceptual gaps for me, that the TODO example lacks.

Again - inspiring work.. 

-- David

David Pidcock

unread,
Jan 6, 2014, 12:05:06 AM1/6/14
to clojur...@googlegroups.com, clo...@googlegroups.com
Ha! Just saw your Sortable example popup in Git!

Very cool.

Curtis Gagliardi

unread,
Jan 6, 2014, 7:25:12 PM1/6/14
to clo...@googlegroups.com, clojur...@googlegroups.com
I watched a few talks from facebook people about React and was impressed, lots of talk about the simplicity of just rerendering everything and pure functions.  I think this is the first time I've been excited about a javascript framework, looking forward to trying it out with Om. 

David Nolen

unread,
Jan 6, 2014, 11:47:06 PM1/6/14
to clojur...@googlegroups.com, clo...@googlegroups.com
The sortable example in the repo is now relatively baked. I'm happy to see React can handle interactive UIs so well.

David Nolen

unread,
Jan 7, 2014, 7:45:52 AM1/7/14
to clojur...@googlegroups.com, clo...@googlegroups.com
If you install locally you need to depend on 

[om "0.1.6-SNAPSHOT"]

I did make a mistake and accidentally did not push the previous version to Clojars which you can depend on as specified in the README:

[om "0.1.5"]


On Tue, Jan 7, 2014 at 6:29 AM, Rick Walsh <rick....@gmail.com> wrote:
Hi Guys,

So... I'm trying to compile a cljs project with OM.

As in instructed above I've:

cloned the repo:

git clone https://github.com/swannodette/om.git

Installed:

lein install

(Output shown below)

Retrieving org/clojure/clojurescript/0.0-2138/clojurescript-0.0-2138.pom from central
Retrieving org/clojure/core.async/0.1.267.0-0d7780-alpha/core.async-0.1.267.0-0d7780-alpha.pom from central
Retrieving com/facebook/react/0.8.0.1/react-0.8.0.1.pom from clojars
Retrieving org/clojure/core.async/0.1.267.0-0d7780-alpha/core.async-0.1.267.0-0d7780-alpha.jar from central
Retrieving org/clojure/clojurescript/0.0-2138/clojurescript-0.0-2138.jar from central
Retrieving com/facebook/react/0.8.0.1/react-0.8.0.1.jar from clojars
Created G:\om\target\om-0.1.6-SNAPSHOT.jar

I then added to my projects cljs a dependency of [om "0.1.6"]

I still get the following error on compilation:

Could not find artifact om:om:jar:0.1.6 in central (http://repo1.maven.org/maven2/)
Could not find artifact om:om:jar:0.1.6 in clojars (https://clojars.org/repo/)

I'm clearly being terribly stupid.

Any suggestions?

--
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.

Alexander Semenov

unread,
Jul 12, 2014, 7:35:21 AM7/12/14
to clojur...@googlegroups.com, clo...@googlegroups.com
Hi, David.

May I ask you - in Om you queue rendering in requestAnimationFrame by passing a function which calls forceUpdate on the affected components. But as I understand forceUpdate does not guarantee to execute immediately and is also queued. So, the rendering should be out of sync with requestAnimationFrame.

Am I misunderstanding something? Can you help to get this, please?

Regards,
Alex.
Reply all
Reply to author
Forward
0 new messages