![Page 1: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/1.jpg)
High Performance Web UI's with Om and React
LambdaJam - Brisbane, 2014
Leonardo Borges @leonardo_borges
www.leonardoborges.com www.thoughtworks.com
![Page 2: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/2.jpg)
About‣ ThoughtWorker ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group
‣ Currently writing “Clojure Reactive Programming”
![Page 3: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/3.jpg)
Functional Programming is on the rise
![Page 4: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/4.jpg)
And that makes us happy
![Page 5: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/5.jpg)
However if you do client-side web development, you’re out of luck
![Page 6: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/6.jpg)
Because Javascript…
[1,3,5].map(parseInt);!// [1, NaN, NaN]!
![Page 7: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/7.jpg)
There are options
![Page 8: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/8.jpg)
Today we’ll see one of them: Clojurescript
![Page 9: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/9.jpg)
What we’ll see
‣ An Overview of React and how it enables fast rendering ‣ Meet Om, a ClojureScript interface to React ‣ Boosting React’s rendering performance with immutable data structures ‣ A simple demo featuring “data binding” and undo functionality
![Page 10: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/10.jpg)
React
‣ Created by Facebook for building user interfaces ‣ The V in MVC ‣ Self-contained components ‣ Doesn’t make assumptions about your stack - can be used with anything
![Page 11: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/11.jpg)
Self-contained components
‣ React combines display logic and DOM generation ‣ Components are themselves loosely coupled ‣ The whole app is re-rendered on every update ‣ Virtual DOM ‣ Efficient diff algorithm
![Page 12: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/12.jpg)
Efficient diff algorithm
‣ Creates a virtual version of the DOM ‣ As the application state changes new DOM trees are generated ‣ React diffs the trees and computes the minimal set of changes ‣ Finally it applies the changes to the real DOM
![Page 13: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/13.jpg)
A simple React componentvar HelloMessage = React.createClass({! displayName: 'HelloMessage',! render: function() {! return React.DOM.div(null, "Hello ", this.props.name);! }!});!!
React.renderComponent(! HelloMessage( {name:"John"} ), mountNode);
![Page 14: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/14.jpg)
No literals?
![Page 15: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/15.jpg)
A simple React component (using the JSX pre-processor)
var HelloMessage = React.createClass({! render: function() {! return <div>Hello {this.props.name}</div>;! }!});!!
React.renderComponent(! <HelloMessage name="John" />, mountNode);
![Page 16: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/16.jpg)
React components are functions from application state to a DOM tree
![Page 17: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/17.jpg)
Now let’s take a leap and look at the same component, written in Om
![Page 18: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/18.jpg)
A simple Om component(def app-state (atom {:name "Leo"}))!!
(defn hello-message [app owner]! (reify om/IRender! (render [_]! (dom/div nil! (str "Hello " (:name app))))))!!
!
(om/root hello-message app-state! {:target (. js/document (getElementById "hello"))})!
![Page 19: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/19.jpg)
Om/React’s component lifecycle
IWillMountIInitState IShouldUpdate
IRender
IRenderState
![Page 20: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/20.jpg)
IShouldUpdate
‣ Called on app state changes but before rendering ‣ This is where React uses its fast diff algorithm ‣ Om components implement the fastest algorithm possible: a simple reference equality check ‣ Generally, you won’t have to implement this
![Page 21: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/21.jpg)
IInitState & IRenderState
‣ Initialise component local state using IInitState ‣ Use IRenderState to work with it and render the component
![Page 22: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/22.jpg)
IInitState & IRenderState(defn counter [app owner]! (reify! om/IInitState! (init-state [_]! {:clicks 0})! om/IRenderState! (render-state [_ state]! (dom/div nil! (str "Clicks " (:clicks state))! (dom/button #js {:onClick! #(om/set-state! owner :clicks (inc (:clicks state)))}! "Click me!")))))!!(om/root counter (atom {})! {:target (. js/document (getElementById "app"))})!
![Page 23: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/23.jpg)
IRender
‣ Same as IRenderState… ‣ …except it doesn’t depend on the component local state to render
![Page 24: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/24.jpg)
IRender(def app-state (atom {:name "Leo"}))!!
(defn hello-message [app owner]! (reify om/IRender! (render [_]! (dom/div nil! (str "Hello " (:name app))))))!!
!
(om/root hello-message app-state! {:target (. js/document (getElementById "hello"))})!
![Page 25: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/25.jpg)
A larger example
![Page 26: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/26.jpg)
A larger example
![Page 27: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/27.jpg)
A reusable editable component(defn editable [text owner]! (reify! om/IInitState! (init-state [_]! {:editing false})! om/IRenderState! (render-state [_ {:keys [editing]}]! (dom/li nil! (dom/span #js {:style (display (not editing))} (om/value text))! (dom/input! #js {:style (display editing)! :value (om/value text)! :onChange #(handle-change % text owner)! :onKeyPress #(when (== (.-keyCode %) 13)! (commit-change text owner))! :onBlur (fn [e] (commit-change text owner))})! (dom/button! #js {:style (display (not editing))! :onClick #(om/set-state! owner :editing true)}! "Edit")))))!
From https://github.com/swannodette/om/wiki/Basic-Tutorial
![Page 28: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/28.jpg)
A reusable editable component(defn editable [text owner]! (reify! om/IInitState! (init-state [_]! {:editing false})! om/IRenderState! (render-state [_ {:keys [editing]}]! (dom/li nil! (dom/span #js {:style (display (not editing))} (om/value text))! (dom/input! #js {:style (display editing)! :value (om/value text)! :onChange #(handle-change % text owner)! :onKeyPress #(when (== (.-keyCode %) 13)! (commit-change text owner))! :onBlur (fn [e] (commit-change text owner))})! (dom/button! #js {:style (display (not editing))! :onClick #(om/set-state! owner :editing true)}! "Edit")))))!
From https://github.com/swannodette/om/wiki/Basic-Tutorial
![Page 29: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/29.jpg)
A reusable editable component(defn editable [text owner]! (reify! om/IInitState! (init-state [_]! {:editing false})! om/IRenderState! (render-state [_ {:keys [editing]}]! (dom/li nil! (dom/span #js {:style (display (not editing))} (om/value text))! (dom/input! #js {:style (display editing)! :value (om/value text)! :onChange #(handle-change % text owner)! :onKeyPress #(when (== (.-keyCode %) 13)! (commit-change text owner))! :onBlur (fn [e] (commit-change text owner))})! (dom/button! #js {:style (display (not editing))! :onClick #(om/set-state! owner :editing true)}! "Edit")))))!
From https://github.com/swannodette/om/wiki/Basic-Tutorial
![Page 30: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/30.jpg)
The speakers view(defn speakers-view [app owner]! (reify! om/IRender! (render [_]! (dom/div nil! (dom/div #js {:id "speakers"! :style #js {:float "left"}}! (dom/h2 nil "Speakers")! (dom/button #js {:onClick undo} "Undo")! (dom/button #js {:onClick reset-app-state} "Reset")! (apply dom/ul nil! (om/build-all speaker-view (speakers app)! {:shared {:app-state app}})))! (om/build speaker-details-view app)))))
This is how you build components
![Page 31: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/31.jpg)
The Sessions view
Same deal as before
(defn sessions-view [app owner]! (reify! om/IRender! (render [_]! (dom/div #js {:id "sessions"}! (dom/h2 nil "Sessions")! (apply dom/ul nil! (map #(om/build editable %) (vals (:sessions app))))))))!
![Page 32: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/32.jpg)
Apps can have multiple roots
(om/root speakers-view app-state! {:target (. js/document (getElementById "speakers"))})!!
(om/root sessions-view app-state! {:target (. js/document (getElementById "sessions"))})!
You can have multiple “mini-apps” inside your main app
Makes it easy to try Om in a specific section/feature
![Page 33: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/33.jpg)
What about “undo” and “reset”?
![Page 34: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/34.jpg)
Implementing undo(def app-state (atom speaker-data))!(def app-history (atom [@app-state]))!!
(add-watch app-state :history! (fn [_ _ _ n]! (when-not (= (last @app-history) n)! (swap! app-history conj n))! (let [c (count @app-history)]! (prn c " Saved items in app history"))))!!
(defn undo []! (when (> (count @app-history) 1)! (swap! app-history pop)! (reset! app-state (last @app-history))))!
![Page 35: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/35.jpg)
Implementing reset
(defn reset-app-state []! (reset! app-state (first @app-history))! (reset! app-history [@app-state]))!
![Page 36: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/36.jpg)
Om/React components are functions from state to DOM trees
![Page 37: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/37.jpg)
With immutable data structures we can access every version of the application state
![Page 38: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/38.jpg)
So we simply update the application state, causing the components to get re-rendered
![Page 39: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/39.jpg)
A bit of live coding
![Page 40: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/40.jpg)
Summary
‣ With Om, you’re not using a crippled template language, you can leverage all of Clojurescript (including other DOM libraries) ‣ Rendering and display logic are inevitably coupled. Om/React acknowledges that a bundles them in components ‣ The whole app is re-rendered on every state change, making it easier to reason about ‣ This is efficient thanks to immutable data structures
![Page 41: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/41.jpg)
Summary
‣ Clojurescript also provides a better development experience with a powerful browser REPL much like what you’d get with Clojure on the JVM ‣ Source maps are here today ‣ Bottom line is that Clojurescript is a serious contender
![Page 42: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/42.jpg)
References
‣ Code: https://github.com/leonardoborges/lambdajam-2014-om-talk ‣ React documentation: http://facebook.github.io/react/ ‣ Om documentation: https://github.com/swannodette/om/wiki/Documentation#build ‣ Basic Tutorial: https://github.com/swannodette/om/wiki/Basic-Tutorial
![Page 43: High Performance Web UI's with Om and React · ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive](https://reader033.vdocument.in/reader033/viewer/2022042407/5f210d83292c1648cc12e92f/html5/thumbnails/43.jpg)
Thanks! Questions?
Leonardo Borges @leonardo_borges
www.leonardoborges.com www.thoughtworks.com