Om and Clojurescript

Embed Size (px)

Citation preview

  • 8/10/2019 Om and Clojurescript

    1/43

    High Performance Web UI'sOm and React

    LambdaJam - Brisbane, 2014

    www.leo

    www

    http://www.thoughtworks.com/http://www.leonardoborges.com/
  • 8/10/2019 Om and Clojurescript

    2/43

    About

    !ThoughtWorker

    !Functional Programming & Clojure

    advocate

    !Founder of the Sydney Clojure User

    Group

    !Currently writing Clojure Reactive

    Programming

  • 8/10/2019 Om and Clojurescript

    3/43

    Functional Programming

    is on the rise

  • 8/10/2019 Om and Clojurescript

    4/43

    And that makes us happy

  • 8/10/2019 Om and Clojurescript

    5/43

    However if you do client-side web

    development, youre out of luck

  • 8/10/2019 Om and Clojurescript

    6/43

    Because Javascript

    [1,3,5].map(parseInt);

    // [1, NaN, NaN]

  • 8/10/2019 Om and Clojurescript

    7/43

    There are options

  • 8/10/2019 Om and Clojurescript

    8/43

    Today well see one of them

    Clojurescript

  • 8/10/2019 Om and Clojurescript

    9/43

    What well see

    !An Overview of React and how it enables fast rendering

    !Meet Om, a ClojureScript interface to React

    !Boosting Reacts rendering performance with immutable da

    !A simple demo featuring data bindingand undo functiona

  • 8/10/2019 Om and Clojurescript

    10/43

    React

    !Created by Facebook for building user interfaces

    !The Vin MVC

    !Self-contained components

    !Doesnt make assumptions about your stack - can be used

  • 8/10/2019 Om and Clojurescript

    11/43

    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

  • 8/10/2019 Om and Clojurescript

    12/43

    Efficient diff algorithm

    !Creates a virtual version of the DOM

    !As the application state changes new DOM trees are gener

    !React diffs the trees and computes the minimal set of chang

    !Finally it applies the changes to the real DOM

  • 8/10/2019 Om and Clojurescript

    13/43

    A simple React component

    varHelloMessage =React.createClass({displayName:'HelloMessage',

    render:function() {

    returnReact.DOM.div(null, "Hello ", this.pro

    }

    });

    React.renderComponent(

    HelloMessage( {name:"John"} ), mountNode);

  • 8/10/2019 Om and Clojurescript

    14/43

    No literals?

  • 8/10/2019 Om and Clojurescript

    15/43

    A simple React component (using t

    JSX pre-processor)

    varHelloMessage =React.createClass({

    render:function() {

    returnHello {this.props.name}

  • 8/10/2019 Om and Clojurescript

    16/43

    React components are functions fro

    application state to a DOM tree

  • 8/10/2019 Om and Clojurescript

    17/43

    Now lets take a leap and look at the s

    component, written in Om

  • 8/10/2019 Om and Clojurescript

    18/43

    A simple Om component

    (def app-state(atom{:name"Leo"}))

    (defn hello-message[appowner]

    (reifyom/IRender

    (render[_]

    (dom/divnil

    (str "Hello "(:nameapp))))))

    (om/roothello-messageapp-state

    {:target(. js/document(getElementById"he

  • 8/10/2019 Om and Clojurescript

    19/43

    Om/Reacts component lifecyc

    IWillMountIInitState IShouldUpdate

  • 8/10/2019 Om and Clojurescript

    20/43

    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

    reference equality check

    !Generally, you wont have to implement this

  • 8/10/2019 Om and Clojurescript

    21/43

    IInitState & IRenderState

    !Initialise component local state using IInitState

    !Use IRenderState to work with it and render the component

  • 8/10/2019 Om and Clojurescript

    22/43

    IInitState & IRenderState(defn counter[appowner]

    (reifyom/IInitState

    (init-state[_]

    {:clicks0})

    om/IRenderState

    (render-state[_state]

    (dom/divnil

    (str "Clicks "(:clicksstate))

    (dom/button#js{:onClick#(om/set-state!owner:clicks(inc (:cl

    "Click me!")))))

    (om/rootcounter(atom{})

    {:target(. js/document(getElementById"app"))})

  • 8/10/2019 Om and Clojurescript

    23/43

    IRender

    !Same as IRenderState

    !except it doesnt depend on the component local state to

  • 8/10/2019 Om and Clojurescript

    24/43

    IRender

    (def app-state(atom{:name"Leo"}))

    (defn hello-message[appowner]

    (reifyom/IRender

    (render[_]

    (dom/divnil

    (str "Hello "(:nameapp))))))

    (om/roothello-messageapp-state

    {:target(. js/document(getElementById"he

  • 8/10/2019 Om and Clojurescript

    25/43

    A larger example

  • 8/10/2019 Om and Clojurescript

    26/43

    A larger example

  • 8/10/2019 Om and Clojurescript

    27/43

    A reusable editable compone(defn editable[textowner]

    (reify

    om/IInitState

    (init-state[_]

    {:editingfalse})

    om/IRenderState

    (render-state[_{:keys[editing]}]

    (dom/linil

    (dom/span#js{:style(display(not editing))} (om/valuet

    (dom/input

    #js{:style(displayediting)

    :value(om/valuetext)

    :onChange#(handle-change%textowner)

    :onKeyPress#(when (== (.-keyCode%) 13)

    (commit-changetextowner))

    :onBlur(fn [e] (commit-changetextowner))})

    (dom/button

    #js{:style(display(not editing))

    :onClick#(om/set-state!owner:editingtrue)}

    "Edit")))))

    From https://github.com/swannodet

    https://github.com/swannodette/om/wiki/Basic-Tutorial
  • 8/10/2019 Om and Clojurescript

    28/43

    A reusable editable compone(defn editable [text owner]

    (reify

    om/IInitState

    (init-state[_]

    {:editingfalse})

    om/IRenderState

    (render-state [_ {:keys [editing]}]

    (dom/li nil

    (dom/span #js {:style (display (not editing))} (om/value t

    (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/swannodet

    https://github.com/swannodette/om/wiki/Basic-Tutorial
  • 8/10/2019 Om and Clojurescript

    29/43

    A reusable editable compone(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/valuet

    (dom/input

    #js{:style(displayediting)

    :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:editingtrue)}

    "Edit")))))

    From https://github.com/swannodet

    https://github.com/swannodette/om/wiki/Basic-Tutorial
  • 8/10/2019 Om and Clojurescript

    30/43

    The speakers view

    (defn speakers-view[appowner]

    (reifyom/IRender

    (render[_]

    (dom/divnil

    (dom/div#js{:id"speakers"

    :style#js{:float"left"}}

    (dom/h2nil"Speakers")

    (dom/button#js{:onClickundo} "Undo"(dom/button#js{:onClickreset-app-st

    (apply dom/ulnil

    (om/build-allspeaker-view(spe

    {:shared{:app-st

    (om/buildspeaker-details-viewapp)))))

    This is how you build

    components

  • 8/10/2019 Om and Clojurescript

    31/43

    The Sessions view

    Same deal as before

    (defn sessions-view[appowner]

    (reify

    om/IRender

    (render[_]

    (dom/div#js{:id"sessions"}

    (dom/h2nil"Sessions")

    (apply dom/ulnil

    (map #(om/buildeditable%) (vals (:sessi

    app))))))))

  • 8/10/2019 Om and Clojurescript

    32/43

    Apps can have multiple roots

    (om/rootspeakers-viewapp-state

    {:target(. js/document(getElementById"speake

    (om/rootsessions-viewapp-state

    {:target(. js/document(getElementById"sessio

    You can have multiple mini-apps inside your main ap

    Makes it easy to try Om in a specific section/feature

  • 8/10/2019 Om and Clojurescript

    33/43

    What about undoand reset?

  • 8/10/2019 Om and Clojurescript

    34/43

    Implementing undo

    (def app-state (atomspeaker-data))

    (def app-history(atom[@app-state]))

    (add-watchapp-state:history

    (fn [___n]

    (when-not (= (last @app-history) n)

    (swap!app-historyconj n))

    (let [c(count @app-history)]

    (prn c" Saved items in app history")

    (defn undo[]

    (when (> (count @app-history) 1)

    (swap!app-historypop)

    (reset!app-state(last @app-history))))

  • 8/10/2019 Om and Clojurescript

    35/43

    Implementing reset

    (defn reset-app-state[]

    (reset!app-state(first @app-history)

    (reset!app-history[@app-state]))

  • 8/10/2019 Om and Clojurescript

    36/43

    Om/React components are functions from

    DOM trees

  • 8/10/2019 Om and Clojurescript

    37/43

    With immutable data structures we can a

    every version of the application stat

  • 8/10/2019 Om and Clojurescript

    38/43

    So we simply update the application state,

    the components to get re-rendered

  • 8/10/2019 Om and Clojurescript

    39/43

    A bit of live coding

  • 8/10/2019 Om and Clojurescript

    40/43

    Summary

    !With Om, youre not using a crippled template language, yo

    leverage all of Clojurescript (including other DOM libraries)

    !Rendering and display logic are inevitably coupled. Om/Re

    acknowledges that a bundles them in components

    !The whole app is re-rendered on every state change, makin

    reason about

    !This is efficient thanks to immutable data structures

    S

  • 8/10/2019 Om and Clojurescript

    41/43

    Summary

    !Clojurescript also provides a better development experienc

    powerful browser REPL much like what youd get with Clojure

    !Source maps are here today

    !Bottom line is that Clojurescript is a serious contender

    R f

  • 8/10/2019 Om and Clojurescript

    42/43

    References

    !Code: https://github.com/leonardoborges/lambdajam-2014-!React documentation: http://facebook.github.io/react/

    !Om documentation: https://github.com/swannodette/om/wik

    Documentation#build

    !Basic Tutorial: https://github.com/swannodette/om/wiki/Basi

    https://github.com/swannodette/om/wiki/Basic-Tutorialhttps://github.com/swannodette/om/wiki/Documentation#build
  • 8/10/2019 Om and Clojurescript

    43/43

    Thanks!Questions?

    Leonardo Borges

    @leonardo_borges

    www.leonardoborges.com

    www.thoughtworks.com

    http://www.thoughtworks.com/http://www.leonardoborges.com/