React in the Land of Parentheses

ClojureScript, Reagent, re-frame


Daniel Janus

React in the Land of Parentheses: ClojureScript, Reagent, re-frame




My journey to ClojureScript

Smyrna: a search tool for collections of texts in Polish

Smyrna 0.2

2011: first version
(backend: Clojure, frontend: Backbone + CoffeeScript)

Smyrna 0.3

2016: new backend,
frontend fully rewritten in
ClojureScript + Reagent + re-frame

ClojureScript what?

ClojureScript syntax


Reagent: a simple component

(defn hello []
    [:h1 "Hello, WarsawJS!"]])

Reagent: composing components

(defn coloured-hello [col]
    [:h1 {:style (str "color: " col)}]

(defn rainbow-hellos []
    (for [col ["red" "orange" "yellow" "green"
               "blue" "indigo" "violet"]]
      [coloured-hello col])])



A stateful container for a value

            (def foo (atom 42))
;=> #<atom 42>

(swap! foo + 10)
;=> nil

(deref foo) ;; or @foo
;=> 52

Reactive atom (ratom)

A variant of Atom that re-renders all components derefing it when the value changes

(def count (reagent.core/atom 0))

(defn counter []
   "Count:" @count
   [:input {:type "button" :value "Click!"
            :on-click #(swap! count inc)}]])


Global and local state

(defn counter []
  (let [count (reagent.core/atom 0)]
    (fn []
       "Count:" @count
       [:input {:type "button" :value "Click!"
                :on-click #(swap! count inc)}]])


It’s MVC, Jim, but not as we know it.

RACES (Reactive-Atom Component Event Subscription) framework

Derived Data All The Way Down!

re-frame is to Reagent what Redux is to React.

re-frame: Unidirectional data flow

re-frame: Counter example

(def initial-state {:count 0})

(register-handler :initialize
  (fn [empty-state event]

(register-handler :bump
  (fn [state event]
    (update-in state [:count] inc)))

re-frame: Counter example (2)

(register-sub :current-count
  (fn [state params]
    (reaction (:count state))))

(defn counter []
  (let [count (subscribe [:current-count])]
    (fn []
      "Count:" @count
      [:button {:on-click #(dispatch [:bump])}

Lessons learned


See you next month at WarsawJS