Date post: | 02-Jun-2018 |
Category: |
Documents |
Upload: | willhslade |
View: | 224 times |
Download: | 0 times |
of 43
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-Tutorial8/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-Tutorial8/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-Tutorial8/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#build8/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/