-
-
Save swannodette/7915826 to your computer and use it in GitHub Desktop.
(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"]}}]}) |
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.
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?
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
.
Why do you need to call
om/render
on line 29? Is it not enough to callrender
(or.renderComponent
) on the root node (i.e.,counters
). Iscounter
not a React component here?