Making Front-end Development Fun again:
Clojurescript & React
by John Stevenson
@jr0cket practicalli.github.io/clojurescript
Javascript as a platform is everywhere
@jr0cket
Many programming
languages have
their quirks…
@jr0cket
www.destroyallsoftware.com/talks/wat
Complex languages
… are not easily
reasoned about by
humans
@jr0cket
Josh Smith - Tweet
Original Gif
ClojureScript
A general purpose language made from decades of design
From Javascript to Clojurescript
f(x) -> (f x)
;; First element of a list is a function call
var foo = “bar” -> (def foo “bar”)
;; bind a name to a value or function
;; values are immutable
@jr0cket
Clojurescript - basic syntax
(ns clojure.awesome ) ;; define a namespace (scoping)
(defn function-name [args] (behaviour)) ;; define a function, with arguments
(function-name data) ;; call a function with the data as its argument
(def name “data-or-value”) ;; bind a name to data within the namespace scope
(let [name “data-or-value”]) ;; bind a name to a data within the let scope (local)
:keyword-name ;; a keyword is a name (symbol) that points to itself
;; Chaining functions: Thread the result of the first fn into the argument of the next fn
(-> (function-a “data”)
(function-b ,,,) ;; In Clojure commas , are whitespace
(function-c ,,, “data”))
Built-in immutable data structures
Model state and any other data with built-in (hash) maps,
vectors (arrays), (linked) lists, (unique) sets
(list 1 2 3 4 5) ‘(“fish” “chips” 42)
(vec ‘(1 2 3 4)) [1 2 3 4]
{:key “value”} {:name “John” :skill “conferencing”}
(set ‘(1 2 3 4 4)) #{1 2 3 4}
Clojure - a few core functions
(map fn collection) ;; map a fn over a collection, return new collection
(reduce fn collection) ;; return the value of combining elements in collection with fn
(for [x collection] (fn x)) ;; iterate over the elements of a collection
(filter fn collection) ;; return a collection of values that comply with the filter fn
(get {:veg “kale” :fruit “kiwi”} :fruit) ;; return value pointed to by keyword
(:fruit {:veg “kale” :fruit “kiwi”}) ;; return value pointed to by keyword
(conj collection value) ;; conjoin a value to the collection
(assoc collection coll) ;; add a collection to the collection
(update {:a 1} :a fn) ;; update value pointed to by the key in a map with the fn
ClojureScript:
Managing complexity
A pragmatic approach to purity
The Complexity Iceberg
- @krisajenkins
● complexity is very
dangerous when hidden
● You can't know what a
function does for certain if it
has side effects
Side Effects
Pure Functions
The results of the function are purely determined by its initial output and its own code
- no external influence, a function only uses local values
- referential transparency (the function can be replaced by its value)
Impure Functions - side causes
Eliminating Side Effects
Functional programming is about eliminating side effects where you can,
controlling them where you can't - @krisajenkins
The features in Functional Programming come from a
desire to reduce side effects
Design idiom:
Composing
functions
together
You can think of functional
design as evaluating one or
more functions in series of
functions
The Map Reduce Sandwich
Clojure - the Map Reduce Sandwich
Clojure - the Map Reduce Sandwich
Pure Functions & Immutability = Parallelism
In simple terms: run the same code across multiple CPU’s / Threads
Managing State
State changes should be managed easily
Concurrency syntax - refs
join-game-safely adds players to ref & alters their account & game account
ClojureScript - Functional Web
Immutability & composable functions for Web Apps
See Clojurescript for Skeptics:
https://www.youtube.com/watch?v=gsffg5xxFQI&t=4s
Google Closure tools & libraries
Examples of Clojurescript
● Goya - pixel editor with undo
https://jackschaedler.github.
io/goya/
● CircleCI
● Style.com
● Klipse - web-based dev tool &
library for live-code examples
in blogs / workshops
Getting Started with
Clojurescript
Common Clojurescript Tooling
Leiningen
- build automation tool for Clojure & Clojurescript
Figwheel (leiningen plugin)
- defacto tool for client side web apps
- live reload
- multi-broadcast (eg simultaneous dev & test outputs)
Full-stack projects: Chestnut
https://github.com/plexus/chestnut
- leiningen template for Clojure/ClojureScript apps based
- with Om, Reagent, or Rum
- instant reloading of Clojure, ClojureScript, and CSS
- browser-connected REPL included
lein new chestnut project-name
Self-hosted Clojurescript Environments
Instant startup times, great for command line tools
Lumo (cross-platform)
- https://github.com/anmonteiro/lumo
Plank (Mac & Linux)
- http://planck-repl.org/
React
Basic concepts of React
https://facebook.github.io/react/
https://github.com/reactjs
React Basics (conceptual)
React provides an efficient way to update the view
Lets code...
Building a conference app...
Reactive Frameworks
All the varieties of life, plus all the Javascript varieties too...
Javascript & Clojurescript frameworks
Javascript
● React.js via cljsjs
● Vue.js ???
Clojurescript
● Om / Om-next
● Reagent / Reframe
● Rum
More at https://clojurescript.org/community/libraries
React.js
Using React.js within Clojurescript
Simple Calculator with React.js
Reagent
Clojurescript can directly use the React.js library thanks to cljsjs.github.io
React.js
React.js
React.js
React.js
React.js
React.js
Om / Om-next
ClojureScript interface to Facebook's React
Om / Om-next
Models the React.js API
Rapidly re-render the UI from the root due via Immutable data structures
- UIs are snapshot-able and undoable without implementation complexity
Om supports features not currently present in React:
- Global state management facilities built in
- Components may have arbitrary data dependencies, not limited to props & state
- Component construction intercepted via :instrument. Simplifies debugging
- Stream all application state deltas via :tx-listen. Simplifies on/offline sync
- Customizable semantics
Om core functions
om.core/IRender
- Render a Om component into the DOM
- uses reify to provide a specific implementation of the om/IRender interface
om.core/IInitState
- maintains a local state (eg. for managing user input data)
om.core/IRenderState
- Render a Om component into the DOM
- renders component on change in local & global state
Om core functions
om.dom/div attributes content
- creates a <div> tag in react
- all react tags need to be wrapped in a div in order to be rendered
- om.dom/… has all the other tags too - h1, h2, p, a … (sablono can be used instead)
#js
- converts clojure maps into Javascript objects
- nest #js functions to to create JS objects - eg. for inline styles
Om Cursors
A cursor is an atom & a path to a location in the atom
app-state :schedule 0
Components use the cursor to refer to pieces of the app state
- without knowing where they are in the state tree
- updating app state is simple as the cursor is in the correct part of the app
state
Reagent
Interactive development
Reagent
Reagent provides a minimalistic interface between ClojureScript and React
- define efficient React components using nothing but plain ClojureScript
functions and data
- describe your UI using a Hiccup syntax
[:div [:h1 “Heading”]
[:div [:p “Paragraph” ]
[:a {:href “/link.html”} “link text”]]]
- define arbitrarily complex UIs using a couple of basic concepts
- fast enough by default that you rarely have to care about performance.
Reagent Core functions
reagent.core/render
- Render a Reagent component into the DOM
- First argument is either a vector (Reagent Hiccup syntax) or a React element
reagent.core/atom
- Like clojure.core/atom, plus it tracks components that deref atom & re-renders them
Helper functions
Reagent used Clojurescript functions for conversion from
- Clojure Maps to Javascript Objects
- Clojurescript vectors to Javascript arrays
clj->js
- convert from Clojurescript to Javascript
js->clj
- convert from Javascript to Clojurescript
Reagent Examples
http://timothypratley.blogspot.co.uk/2017/01/reagent-deep-dive-part-1.html
- Uses Klipse to display interactive code snippets for Reagent
- Includes use of SVG and Web3D libraries too
Graph example - http://leaderboardx.herokuapp.com/
Reframe
A micro-framework for Reagent
Re-frame
a pattern for writing SPAs in ClojureScript, using Reagent.
a framework with pure functions which transform data
Architecturally implements "a perpetual loop".
Build apps by writing pure functions for certain parts of
the loop that transform the data
- Re-frame looks after the conveyance of data around the
loop, into and out of the transforming functions you write
- tag line of "Derived Values, Flowing".
Rum
A micro-framework for Reagent
Rum
Rum is a client/server library for HTML UI. In ClojureScript, it works as React wrapper, in Clojure, it is a static HTML
generator.
- Simple semantics: Rum is arguably smaller, simpler and more straightforward than React itself.
- Decomplected: Rum is a library, not a framework. Use only the parts you need, throw away or replace what you don’t
need, combine different approaches in a single app, or even combine Rum with other frameworks.
- No enforced state model: Unlike Om, Reagent or Quiescent, Rum does not dictate where to keep your state. Instead, it
works well with any storage: persistent data structures, atoms, DataScript, JavaScript objects, localStorage or any custom
solution you can think of.
- Extensible: the API is stable and explicitly defined, including the API between Rum internals. It lets you build custom
behaviours that change components in significant ways.
- Minimal codebase: You can become a Rum expert just by reading its source code (~900 lines).
Rum - at ClojureX
https://skillsmatter.com/skillscasts/9149-modern-web-apps-with-rum
Other ClojureScript examples
Interactive development
Figwheel (flappy birds example)
Take a journey into Clojurescript
Clojurescript.org & ClojureDocs.org
londonclojurians.org
- 4 events per month
- Possibly the most active language-specific
developer communitie in London
Learning by teaching others
I really started thinking in Clojure when I started talking to & teaching others
- Coding dojos
- talks on Clojure (starting with the basics, showing the art of the possible)
- moving on to running conferences
- workshops at hack days
Thank you
@jr0cket
jr0cket.co.uk
slideshare.net/jr0cket

ClojureScript - Making Front-End development Fun again - John Stevenson - Codemotion Amsterdam 2017

  • 1.
    Making Front-end DevelopmentFun again: Clojurescript & React by John Stevenson @jr0cket practicalli.github.io/clojurescript
  • 2.
    Javascript as aplatform is everywhere @jr0cket
  • 3.
    Many programming languages have theirquirks… @jr0cket www.destroyallsoftware.com/talks/wat
  • 4.
    Complex languages … arenot easily reasoned about by humans @jr0cket Josh Smith - Tweet Original Gif
  • 5.
    ClojureScript A general purposelanguage made from decades of design
  • 6.
    From Javascript toClojurescript f(x) -> (f x) ;; First element of a list is a function call var foo = “bar” -> (def foo “bar”) ;; bind a name to a value or function ;; values are immutable @jr0cket
  • 7.
    Clojurescript - basicsyntax (ns clojure.awesome ) ;; define a namespace (scoping) (defn function-name [args] (behaviour)) ;; define a function, with arguments (function-name data) ;; call a function with the data as its argument (def name “data-or-value”) ;; bind a name to data within the namespace scope (let [name “data-or-value”]) ;; bind a name to a data within the let scope (local) :keyword-name ;; a keyword is a name (symbol) that points to itself ;; Chaining functions: Thread the result of the first fn into the argument of the next fn (-> (function-a “data”) (function-b ,,,) ;; In Clojure commas , are whitespace (function-c ,,, “data”))
  • 8.
    Built-in immutable datastructures Model state and any other data with built-in (hash) maps, vectors (arrays), (linked) lists, (unique) sets (list 1 2 3 4 5) ‘(“fish” “chips” 42) (vec ‘(1 2 3 4)) [1 2 3 4] {:key “value”} {:name “John” :skill “conferencing”} (set ‘(1 2 3 4 4)) #{1 2 3 4}
  • 9.
    Clojure - afew core functions (map fn collection) ;; map a fn over a collection, return new collection (reduce fn collection) ;; return the value of combining elements in collection with fn (for [x collection] (fn x)) ;; iterate over the elements of a collection (filter fn collection) ;; return a collection of values that comply with the filter fn (get {:veg “kale” :fruit “kiwi”} :fruit) ;; return value pointed to by keyword (:fruit {:veg “kale” :fruit “kiwi”}) ;; return value pointed to by keyword (conj collection value) ;; conjoin a value to the collection (assoc collection coll) ;; add a collection to the collection (update {:a 1} :a fn) ;; update value pointed to by the key in a map with the fn
  • 10.
  • 11.
    The Complexity Iceberg -@krisajenkins ● complexity is very dangerous when hidden ● You can't know what a function does for certain if it has side effects
  • 12.
  • 13.
    Pure Functions The resultsof the function are purely determined by its initial output and its own code - no external influence, a function only uses local values - referential transparency (the function can be replaced by its value)
  • 14.
    Impure Functions -side causes
  • 15.
    Eliminating Side Effects Functionalprogramming is about eliminating side effects where you can, controlling them where you can't - @krisajenkins The features in Functional Programming come from a desire to reduce side effects
  • 16.
    Design idiom: Composing functions together You canthink of functional design as evaluating one or more functions in series of functions
  • 17.
  • 18.
    Clojure - theMap Reduce Sandwich
  • 19.
    Clojure - theMap Reduce Sandwich
  • 20.
    Pure Functions &Immutability = Parallelism In simple terms: run the same code across multiple CPU’s / Threads
  • 21.
    Managing State State changesshould be managed easily
  • 22.
    Concurrency syntax -refs join-game-safely adds players to ref & alters their account & game account
  • 23.
    ClojureScript - FunctionalWeb Immutability & composable functions for Web Apps
  • 24.
    See Clojurescript forSkeptics: https://www.youtube.com/watch?v=gsffg5xxFQI&t=4s
  • 25.
  • 26.
    Examples of Clojurescript ●Goya - pixel editor with undo https://jackschaedler.github. io/goya/ ● CircleCI ● Style.com ● Klipse - web-based dev tool & library for live-code examples in blogs / workshops
  • 27.
  • 28.
    Common Clojurescript Tooling Leiningen -build automation tool for Clojure & Clojurescript Figwheel (leiningen plugin) - defacto tool for client side web apps - live reload - multi-broadcast (eg simultaneous dev & test outputs)
  • 29.
    Full-stack projects: Chestnut https://github.com/plexus/chestnut -leiningen template for Clojure/ClojureScript apps based - with Om, Reagent, or Rum - instant reloading of Clojure, ClojureScript, and CSS - browser-connected REPL included lein new chestnut project-name
  • 30.
    Self-hosted Clojurescript Environments Instantstartup times, great for command line tools Lumo (cross-platform) - https://github.com/anmonteiro/lumo Plank (Mac & Linux) - http://planck-repl.org/
  • 31.
  • 32.
  • 33.
    React Basics (conceptual) Reactprovides an efficient way to update the view
  • 34.
    Lets code... Building aconference app...
  • 35.
    Reactive Frameworks All thevarieties of life, plus all the Javascript varieties too...
  • 36.
    Javascript & Clojurescriptframeworks Javascript ● React.js via cljsjs ● Vue.js ??? Clojurescript ● Om / Om-next ● Reagent / Reframe ● Rum More at https://clojurescript.org/community/libraries
  • 37.
  • 38.
  • 39.
    Reagent Clojurescript can directlyuse the React.js library thanks to cljsjs.github.io
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
    Om / Om-next ClojureScriptinterface to Facebook's React
  • 47.
    Om / Om-next Modelsthe React.js API Rapidly re-render the UI from the root due via Immutable data structures - UIs are snapshot-able and undoable without implementation complexity Om supports features not currently present in React: - Global state management facilities built in - Components may have arbitrary data dependencies, not limited to props & state - Component construction intercepted via :instrument. Simplifies debugging - Stream all application state deltas via :tx-listen. Simplifies on/offline sync - Customizable semantics
  • 48.
    Om core functions om.core/IRender -Render a Om component into the DOM - uses reify to provide a specific implementation of the om/IRender interface om.core/IInitState - maintains a local state (eg. for managing user input data) om.core/IRenderState - Render a Om component into the DOM - renders component on change in local & global state
  • 49.
    Om core functions om.dom/divattributes content - creates a <div> tag in react - all react tags need to be wrapped in a div in order to be rendered - om.dom/… has all the other tags too - h1, h2, p, a … (sablono can be used instead) #js - converts clojure maps into Javascript objects - nest #js functions to to create JS objects - eg. for inline styles
  • 50.
    Om Cursors A cursoris an atom & a path to a location in the atom app-state :schedule 0 Components use the cursor to refer to pieces of the app state - without knowing where they are in the state tree - updating app state is simple as the cursor is in the correct part of the app state
  • 52.
  • 54.
    Reagent Reagent provides aminimalistic interface between ClojureScript and React - define efficient React components using nothing but plain ClojureScript functions and data - describe your UI using a Hiccup syntax [:div [:h1 “Heading”] [:div [:p “Paragraph” ] [:a {:href “/link.html”} “link text”]]] - define arbitrarily complex UIs using a couple of basic concepts - fast enough by default that you rarely have to care about performance.
  • 55.
    Reagent Core functions reagent.core/render -Render a Reagent component into the DOM - First argument is either a vector (Reagent Hiccup syntax) or a React element reagent.core/atom - Like clojure.core/atom, plus it tracks components that deref atom & re-renders them
  • 56.
    Helper functions Reagent usedClojurescript functions for conversion from - Clojure Maps to Javascript Objects - Clojurescript vectors to Javascript arrays clj->js - convert from Clojurescript to Javascript js->clj - convert from Javascript to Clojurescript
  • 57.
    Reagent Examples http://timothypratley.blogspot.co.uk/2017/01/reagent-deep-dive-part-1.html - UsesKlipse to display interactive code snippets for Reagent - Includes use of SVG and Web3D libraries too Graph example - http://leaderboardx.herokuapp.com/
  • 59.
  • 60.
    Re-frame a pattern forwriting SPAs in ClojureScript, using Reagent. a framework with pure functions which transform data Architecturally implements "a perpetual loop". Build apps by writing pure functions for certain parts of the loop that transform the data - Re-frame looks after the conveyance of data around the loop, into and out of the transforming functions you write - tag line of "Derived Values, Flowing".
  • 61.
  • 62.
    Rum Rum is aclient/server library for HTML UI. In ClojureScript, it works as React wrapper, in Clojure, it is a static HTML generator. - Simple semantics: Rum is arguably smaller, simpler and more straightforward than React itself. - Decomplected: Rum is a library, not a framework. Use only the parts you need, throw away or replace what you don’t need, combine different approaches in a single app, or even combine Rum with other frameworks. - No enforced state model: Unlike Om, Reagent or Quiescent, Rum does not dictate where to keep your state. Instead, it works well with any storage: persistent data structures, atoms, DataScript, JavaScript objects, localStorage or any custom solution you can think of. - Extensible: the API is stable and explicitly defined, including the API between Rum internals. It lets you build custom behaviours that change components in significant ways. - Minimal codebase: You can become a Rum expert just by reading its source code (~900 lines).
  • 63.
    Rum - atClojureX https://skillsmatter.com/skillscasts/9149-modern-web-apps-with-rum
  • 64.
  • 65.
  • 66.
    Take a journeyinto Clojurescript
  • 67.
  • 69.
    londonclojurians.org - 4 eventsper month - Possibly the most active language-specific developer communitie in London
  • 70.
    Learning by teachingothers I really started thinking in Clojure when I started talking to & teaching others - Coding dojos - talks on Clojure (starting with the basics, showing the art of the possible) - moving on to running conferences - workshops at hack days
  • 71.