Skip to content

Instantly share code, notes, and snippets.

@swannodette
Last active December 30, 2015 10:09
Show Gist options
  • Save swannodette/7813518 to your computer and use it in GitHub Desktop.
Save swannodette/7813518 to your computer and use it in GitHub Desktop.
(ns react-cljs.core
(:require-macros [reactjs.macros :refer [pure]])
(:require React [reactjs.core :as r]))
(enable-console-print!)
(declare render-ui)
(defn render-counter [id state cb]
(pure state
(React/DOM.div nil
(React/DOM.label nil (:count state))
(React/DOM.button
(js-obj "onClick" #(cb (update-in state [:count] inc)))
"+")
(React/DOM.button
(js-obj "onClick" #(cb (update-in state [:count] dec)))
"-"))))
(defn render-ui [n]
(let [state (atom (zipmap (range n) (repeat {:count 0})))]
((fn loop []
(let [state' @state]
(React/renderComponent
(pure state'
(React/DOM.div nil
(into-array
(concat
[(React/DOM.h1 nil "A Counting Widget!")]
(map (fn [n]
(render-counter n (get state' n)
#(do (swap! state assoc n %) (loop))))
(range n))))))
js/document.body))))))
(render-ui 10)
(ns reactjs.macros)
(defmacro pure [value children]
`(reactjs.core/Pure. (cljs.core/js-obj "value" ~value) (fn [] ~children)))
(ns reactjs.core
(:require React))
(def Pure
(React/createClass
(js-obj
"shouldComponentUpdate"
(fn [next-props next-state]
(this-as this
(not (= (.. this -props -value) (.-value next-props)))))
"render"
(fn []
(this-as this
((.. this -props -children)))))))
@ericnormand
Copy link

This will indeed rock the web.

@gdeer81
Copy link

gdeer81 commented Dec 8, 2013

I finally started getting used to Angular, and now Reactjs comes along and makes me rethink best practices. Now I see that no matter what the framework du jour, always bet on Clojurescript. Good job

@noprompt
Copy link

This plus the hiccup style templating I borrowed from pump is turning in to a knockout punch.

I'm still evaluating these macros but so far it's been very nice.

(defmacro deftemplate [name bindings & body]
  `(defn ~name ~bindings
     (react/html ~@body)))

(defmacro defhtmlcomponent [name bindings & body]
  (let [data-sym (first bindings)]
    `(defn ~name ~bindings
       (pure ~data-sym (react/html ~@body)))))

Here's a basic example of how it looks in action.

(deftemplate link-to [href & content]
  [:a {:href href} content])

(defhtmlcomponent SiteNavigation [links]
  [:div {:id "site-navigation"}
   [:ul 
    (for [link links]
      [:li
       (link-to (:href link) (:description link))])]])

(react/render-component
 (SiteNavigation [{:href "/home" :description "Home"}
                  {:href "/about" :description "About us"}
                  {:href "/contact" :description "Contact us"}])
 site-navigation-mount-point)

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