React in the Land of Parentheses

ClojureScript, Reagent, re-frame

Speaker

Daniel Janus

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

2016-08-10

@nathell

Me

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

Reagent: a simple component

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

Reagent: composing components

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

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

        

Atom

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 []
  [:div
   "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 []
      [:div
       "Count:" @count
       [:input {:type "button" :value "Click!"
                :on-click #(swap! count inc)}]])
        

re-frame

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]
    initial-state))

(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])}
        "Click!"]]))
        

Lessons learned

Questions?

See you next month at WarsawJS