Instantly share code, notes, and snippets.

Embed
What would you like to do?
(ns react-cljs.core
(:require-macros [cljs.core.async.macros :refer [go]])
(:require [om.core :as om]
[om.dom :as dom :include-macros true]
[cljs.core.async :refer [>! <! chan put! sliding-buffer]]))
(enable-console-print!)
(def app-state
(atom {:counters (into [] (map (fn [n] {:id n :count 0}) (range 10)))}))
(defn counter [data chans]
(dom/component
(dom/div nil
(dom/label nil (:count data))
(dom/button
#js {:onClick
(fn [e]
(do
(om/update! data [:count] inc)
(put! (:last-clicked chans)
(-> data meta :om.core/path))))}
"+")
(dom/button
#js {:onClick (fn [e] (om/update! data [:count] dec))}
"-"))))
(defn counters []
(let [last-clicked (chan (sliding-buffer 1))
chans {:last-clicked last-clicked}]
(om/root
app-state
(fn [data]
(reify
dom/IWillMount
(-will-mount [_ _]
(go (while true
(om/replace! data [:message] (<! last-clicked)))))
dom/IRender
(-render [_ _]
(dom/div nil
(into-array
(concat
[(dom/h1 #js {:key "head"} "A Counting Widget!")
(dom/div #js {:style
(if (:message data)
#js {:display "block"}
#js {:display "none"})}
(when-let [lc (:message data)]
(str "Last clicked item was " (last lc))))]
(map #(om/render counter data
{:path [:counters %] :opts chans :key :id})
(range (count (:counters data))))))))))
js/document.body)))
(counters)
(defproject react-cljs "0.1.0-SNAPSHOT"
:description "FIXME: write this!"
:url "http://example.com/FIXME"
:dependencies [[org.clojure/clojure "1.5.1"]
[org.clojure/clojurescript "0.0-2122"]
[org.clojure/core.async "0.1.267.0-0d7780-alpha"]
[om "0.1.0"]]
:plugins [[lein-cljsbuild "1.0.0"]]
:source-paths ["src"]
:cljsbuild {
:builds [{:id "dev"
:source-paths ["src"]
:compiler {
:output-to "main.js"
:output-dir "out"
:optimizations :none
:source-map true
:foreign-libs [{:file "om/react.js"
:provides ["React"]}]
:externs ["om/externs/react.js"]}}]})
@jonase

This comment has been minimized.

jonase commented Dec 12, 2013

Why do you need to call om/render on line 29? Is it not enough to call render (or .renderComponent) on the root node (i.e., counters). Is counter not a React component here?

@swannodette

This comment has been minimized.

Owner

swannodette commented Dec 12, 2013

om/render needs to do some work behind the scenes to ensure that the correct pure owner component is constructed on data for efficient diffing and lazy children component construction.

@jonase

This comment has been minimized.

jonase commented Dec 13, 2013

This is exciting stuff! Another quick question.. Is the path argument also an optimization? If I understand React correctly there is no explicit path to components in the virtual dom tree. Or is path only a path into the state map which contains the data maintained by a particular component (similar to what pedestal does)?

Also, data is kind of equivalent to state in React, correct?

@swannodette

This comment has been minimized.

Owner

swannodette commented Dec 14, 2013

path is so that components can update their own state in the tree, it gives us the power of setState without actually needing setState. It's no longer an explicit parameter, it's metadata on the data received by a component. Yes data is like state.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment