SlideShare a Scribd company logo
ClojureScript
interfaces to React
Michiel Borkent
@borkdude
Øredev, November 6th 2014
Michiel Borkent (@borkdude)
● Clojure(Script) developer at
● Clojure since 2009
● Former lecturer, taught Clojure
Full Clojure stack example @ Finalist
Commercial app.
Fairly complex UI
● Menu: 2 "pages"
Page 1:
Dashboard. Create new or select
existing entity to work on.
Then:
● Wizard 1
○ Step 1..5
○ Each step has a
component
● Wizard 1 - Step2
○ Wizard 2
■ Step 1'
■ Step 2'
Full Clojure stack examples @ Finalist
Step 2 of inner wizard:
● Three dependent dropdowns
+ backing ajax calls
● Crud table of added items +
option to remove
● When done: create
something based on all of
this on server and reload
entire "model" based on
what server says
Because of React + Om we didn't
have to think about updating DOM
performantly or keeping "model" up
to date.
Agenda
● What is React?
● Om
● Reagent
What is React?
React
● Developed by Facebook
● Helps building reusable and composable UI
components
● Unidirectional Data Flow
● Less need for re-rendering logic
● Leverages virtual DOM for performance
● Can render on server to make apps crawlable
/** @jsx React.DOM */
var Counter = React.createClass({
getInitialState: function() {
return {counter: this.props.initialCount};
},
inc: function() {
this.setState({counter: this.state.counter + 1});
},
render: function() {
return <div>
{this.state.counter}
<button onClick={this.inc}>x</button>
</div>;
}
});
React.renderComponent(<Counter initialCount={10}/>, document.body);
ClojureScript interfaces
Prior knowledge
(def my-atom (atom 0))
@my-atom ;; 0
(reset! my-atom 1)
(reset! my-atom (inc @my-atom)) ;; bad idiom
(swap! my-atom (fn [old-value]
(inc old-value)))
(swap! my-atom inc) ;; same
@my-atom ;; 4
Before React: manual DOM edits
(add-watch greeting-form :form-change-key
(fn [k r o n]
(dispatch/fire :form-change {:old o :new n})))
(dispatch/react-to #{:form-change}
(fn [_ m]
(doseq [s (form-fields-status m)]
(render-form-field s))
(render-button [(-> m :old :status)
(-> m :new :status)] )))
source: http://clojurescriptone.com/documentation.html
ClojureScript interfaces
Quiescent - Luke vanderHart
Om - David Nolen
Reagent (was: Cloact) - Dan Holmsand
React + ClojureScript
Both Om and Reagent leverage:
● immutability for faster comparison in
shouldComponentUpdate
● Fewer redraws by batching updates with
requestAnimationFrame
Om
● Opinionated library by David Nolen
● One atom for app state
● Props: narrowed scope of app state (cursor)
(def app-state (atom {:counter1 {:count 10}
:counter2 {:count 11}}))
(defn main [app owner]
(om/component
(dom/div nil
(om/build counter (:counter1 app))
(om/build counter (:counter2 app)))))
Om
● Communication between components via
○ setting init-state / state (parent -> child)
○ callbacks (child -> parent)
○ app-state
○ core.async
● Explicit hooks into React lifecycle via ClojureScript
protocols
● Follows React semantics closely (e.g. local state
changes cause re-rendering)
(def app-state (atom {:counter 10}))
(defn app-state-counter [app owner]
(reify
om/IRender
(render [_]
(dom/div nil
(:counter app)
(dom/button
#js {:onClick
#(om/transact! app :counter inc)}
"x")))))
(om/root
app-state-counter
app-state
{:target (. js/document (getElementById "app"))})
Goya pixel editor
Some catches
● Large vocabulary around cursors: app(-state), owner, build,
cursors, ref-cursors, root, update!, update-state!,
transact!, opts
● Cursor behaves differently depending on lifecycle
● Strong correspondence between component tree structure and app state
structure (ref-cursors are supposed to solve this)
● Heavy use of callbacks or core.async to make components reusable
(should not rely on app-state)
● Omission of #js reader literal, :className instead of :class, or nil if no
attributes used, fails silently or cryptic error messages
Reagent
Reagent
Uses RAtoms for state management
Components are 'just functions'™ that
● must return something renderable by React
● can deref RAtom(s)
● can accept props as args
● may return a closure, useful for setting up initial state
Reagent
● Components should be called like
[component args] instead of
(component args)
● Components are re-rendered when
○ props (args) change
○ referred RAtoms change
● Hook into React lifecycle via metadata on component functions
(def component
(with-meta
(fn [x]
[:p "Hello " x ", it is " (:day @time-state)])
{:component-will-mount #(println "called before mounting")
:component-did-update #(js/alert "called after updating")} ))
(def count-state (atom 10))
(defn counter []
[:div
@count-state
[:button {:on-click #(swap! count-state inc)}
"x"]])
(reagent/render-component [counter]
(js/document.getElementById "app"))
RAtom
(defn local-counter [start-value]
(let [count-state (atom start-value)]
(fn []
[:div
@count-state
[:button {:on-click #(swap! count-state inc)}
"x"]])))
(reagent/render-component [local-counter 10]
(js/document.getElementById "app"))
local
RAtom
CRUD!
(def animals-state (atom #{}))
(go (let [response
(<! (http/get "/animals"))
data (:body response)]
(reset! animals-state (set data))))
RAtom with set containing
animal hash-maps
(...
{:id 2,
:type :animal,
:name "Yellow-backed duiker",
:species "Cephalophus silvicultor"}
{:id 1,
:type :animal,
:name "Painted-snipe",
:species "Rostratulidae"}
Render all animals from state
(defn animals []
[:div
[:table.table.table-striped
[:thead
[:tr
[:th "Name"] [:th "Species"] [:th ""] [:th ""]]]
[:tbody
(map (fn [a]
^{:key (str "animal-row-" (:id a))}
[animal-row a])
(sort-by :name @animals-state))
[animal-form]]]])
a row component
for each animal
form to create new animal
key needed for React to keep track of rows
(defn animal-row [a]
(let [row-state (atom {:editing? false
:name (:name a)
:species (:species a)})
current-animal (fn []
(assoc a
:name (:name @row-state)
:species (:species @row-state)))]
(fn []
[:tr
[:td [editable-input row-state :name]]
[:td [editable-input row-state :species]]
[:td [:button.btn.btn-primary.pull-right
{:disabled (not (input-valid? row-state))
:onClick (fn []
(when (:editing? @row-state)
(update-animal! (current-animal)))
(swap! row-state update-in [:editing?] not))}
(if (:editing? @row-state) "Save" "Edit")]]
[:td [:button.btn.pull-right.btn-danger
{:onClick #(remove-animal! (current-animal))}
"u00D7"]]])))
(defn field-input-handler
"Returns a handler that updates value in atom map,
under key, with value from onChange event"
[atom key]
(fn [e]
(swap! atom
assoc key
(.. e -target -value))))
(defn input-valid? [atom]
(and (seq (-> @atom :name))
(seq (-> @atom :species))))
(defn editable-input [atom key]
(if (:editing? @atom)
[:input {:type "text"
:value (get @atom key)
:onChange (field-input-handler atom key)}]
[:p (get @atom key)]))
(defn remove-animal! [a]
(go (let [response
(<! (http/delete (str "/animals/"
(:id a))))]
(if (= (:status response)
200)
(swap! animals-state remove-by-id (:id a))))))
(defn update-animal! [a]
(go (let [response
(<! (http/put (str "/animals/" (:id a))
{:edn-params a}))
updated-animal (:body response)]
(swap! animals-state
(fn [old-state]
(conj
(remove-by-id old-state (:id a))
updated-animal))))))
replace updated
animal retrieved
from server
if server says:
"OK!", remove
animal from
CRUD table
Live demo
If you want to try yourself. Code and slides at:
https://github.com/borkdude/oredev2014
My experience with Om and Reagent
● Both awesome
● Added value to React
● Om encourages snapshot-able apps but:
○ surprises
○ large vocabulary
● Reagent
○ easy to learn and use
○ readable

More Related Content

What's hot

Clojurian Conquest
Clojurian ConquestClojurian Conquest
Clojurian Conquest
Kent Ohashi
 
Kotlin in action
Kotlin in actionKotlin in action
Kotlin in action
Ciro Rizzo
 
Skiron - Experiments in CPU Design in D
Skiron - Experiments in CPU Design in DSkiron - Experiments in CPU Design in D
Skiron - Experiments in CPU Design in D
Mithun Hunsur
 
Streams in Node.js
Streams in Node.jsStreams in Node.js
Streams in Node.js
Sebastian Springer
 
Best Practices in Qt Quick/QML - Part III
Best Practices in Qt Quick/QML - Part IIIBest Practices in Qt Quick/QML - Part III
Best Practices in Qt Quick/QML - Part III
ICS
 
JDKs 10 to 14 (and beyond)
JDKs 10 to 14 (and beyond)JDKs 10 to 14 (and beyond)
JDKs 10 to 14 (and beyond)
Scott Leberknight
 
Serving QML applications over the network
Serving QML applications over the networkServing QML applications over the network
Serving QML applications over the network
Jeremy Lainé
 
Return of c++
Return of c++Return of c++
Return of c++
Yongwei Wu
 
Kotlin hands on - MorningTech ekito 2017
Kotlin hands on - MorningTech ekito 2017Kotlin hands on - MorningTech ekito 2017
Kotlin hands on - MorningTech ekito 2017
Arnaud Giuliani
 
TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript Introduction
Dmitry Sheiko
 
Android antipatterns
Android antipatternsAndroid antipatterns
Android antipatterns
Bartosz Kosarzycki
 
A Recovering Java Developer Learns to Go
A Recovering Java Developer Learns to GoA Recovering Java Developer Learns to Go
A Recovering Java Developer Learns to Go
Matt Stine
 
Swift - One step forward from Obj-C
Swift -  One step forward from Obj-CSwift -  One step forward from Obj-C
Swift - One step forward from Obj-C
Nissan Tsafrir
 
06 - Qt Communication
06 - Qt Communication06 - Qt Communication
06 - Qt Communication
Andreas Jakl
 
Develop your next app with kotlin @ AndroidMakersFr 2017
Develop your next app with kotlin @ AndroidMakersFr 2017Develop your next app with kotlin @ AndroidMakersFr 2017
Develop your next app with kotlin @ AndroidMakersFr 2017
Arnaud Giuliani
 
Vladymyr Bahrii Understanding polymorphism in C++ 16.11.17
Vladymyr Bahrii Understanding polymorphism in C++ 16.11.17Vladymyr Bahrii Understanding polymorphism in C++ 16.11.17
Vladymyr Bahrii Understanding polymorphism in C++ 16.11.17
LogeekNightUkraine
 
AST Transformations at JFokus
AST Transformations at JFokusAST Transformations at JFokus
AST Transformations at JFokus
HamletDRC
 
Seeking Clojure
Seeking ClojureSeeking Clojure
Seeking Clojure
chrisriceuk
 
Practical REPL-driven Development with Clojure
Practical REPL-driven Development with ClojurePractical REPL-driven Development with Clojure
Practical REPL-driven Development with Clojure
Kent Ohashi
 
JavaScript in 2016
JavaScript in 2016JavaScript in 2016
JavaScript in 2016
Codemotion
 

What's hot (20)

Clojurian Conquest
Clojurian ConquestClojurian Conquest
Clojurian Conquest
 
Kotlin in action
Kotlin in actionKotlin in action
Kotlin in action
 
Skiron - Experiments in CPU Design in D
Skiron - Experiments in CPU Design in DSkiron - Experiments in CPU Design in D
Skiron - Experiments in CPU Design in D
 
Streams in Node.js
Streams in Node.jsStreams in Node.js
Streams in Node.js
 
Best Practices in Qt Quick/QML - Part III
Best Practices in Qt Quick/QML - Part IIIBest Practices in Qt Quick/QML - Part III
Best Practices in Qt Quick/QML - Part III
 
JDKs 10 to 14 (and beyond)
JDKs 10 to 14 (and beyond)JDKs 10 to 14 (and beyond)
JDKs 10 to 14 (and beyond)
 
Serving QML applications over the network
Serving QML applications over the networkServing QML applications over the network
Serving QML applications over the network
 
Return of c++
Return of c++Return of c++
Return of c++
 
Kotlin hands on - MorningTech ekito 2017
Kotlin hands on - MorningTech ekito 2017Kotlin hands on - MorningTech ekito 2017
Kotlin hands on - MorningTech ekito 2017
 
TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript Introduction
 
Android antipatterns
Android antipatternsAndroid antipatterns
Android antipatterns
 
A Recovering Java Developer Learns to Go
A Recovering Java Developer Learns to GoA Recovering Java Developer Learns to Go
A Recovering Java Developer Learns to Go
 
Swift - One step forward from Obj-C
Swift -  One step forward from Obj-CSwift -  One step forward from Obj-C
Swift - One step forward from Obj-C
 
06 - Qt Communication
06 - Qt Communication06 - Qt Communication
06 - Qt Communication
 
Develop your next app with kotlin @ AndroidMakersFr 2017
Develop your next app with kotlin @ AndroidMakersFr 2017Develop your next app with kotlin @ AndroidMakersFr 2017
Develop your next app with kotlin @ AndroidMakersFr 2017
 
Vladymyr Bahrii Understanding polymorphism in C++ 16.11.17
Vladymyr Bahrii Understanding polymorphism in C++ 16.11.17Vladymyr Bahrii Understanding polymorphism in C++ 16.11.17
Vladymyr Bahrii Understanding polymorphism in C++ 16.11.17
 
AST Transformations at JFokus
AST Transformations at JFokusAST Transformations at JFokus
AST Transformations at JFokus
 
Seeking Clojure
Seeking ClojureSeeking Clojure
Seeking Clojure
 
Practical REPL-driven Development with Clojure
Practical REPL-driven Development with ClojurePractical REPL-driven Development with Clojure
Practical REPL-driven Development with Clojure
 
JavaScript in 2016
JavaScript in 2016JavaScript in 2016
JavaScript in 2016
 

Similar to ClojureScript interfaces to React

ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015
Michiel Borkent
 
Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript
Progscon 2017: Taming the wild fronteer - Adventures in ClojurescriptProgscon 2017: Taming the wild fronteer - Adventures in Clojurescript
Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript
John Stevenson
 
High Performance web apps in Om, React and ClojureScript
High Performance web apps in Om, React and ClojureScriptHigh Performance web apps in Om, React and ClojureScript
High Performance web apps in Om, React and ClojureScript
Leonardo Borges
 
ClojureScript - Making Front-End development Fun again - John Stevenson - Cod...
ClojureScript - Making Front-End development Fun again - John Stevenson - Cod...ClojureScript - Making Front-End development Fun again - John Stevenson - Cod...
ClojureScript - Making Front-End development Fun again - John Stevenson - Cod...
Codemotion
 
Exploring Clojurescript
Exploring ClojurescriptExploring Clojurescript
Exploring Clojurescript
Luke Donnet
 
Front-end God Mode with Reagent and Figwheel
Front-end God Mode with Reagent and FigwheelFront-end God Mode with Reagent and Figwheel
Front-end God Mode with Reagent and Figwheel
David Kay
 
Reactive, component 그리고 angular2
Reactive, component 그리고  angular2Reactive, component 그리고  angular2
Reactive, component 그리고 angular2
Jeado Ko
 
React native
React nativeReact native
Road to react hooks
Road to react hooksRoad to react hooks
Road to react hooks
Younes (omar) Meliani
 
Ember.js - A JavaScript framework for creating ambitious web applications
Ember.js - A JavaScript framework for creating ambitious web applications  Ember.js - A JavaScript framework for creating ambitious web applications
Ember.js - A JavaScript framework for creating ambitious web applications
Juliana Lucena
 
Android Support Library
Android Support LibraryAndroid Support Library
Android Support Library
Alexey Ustenko
 
Functional Reactive Programming / Compositional Event Systems
Functional Reactive Programming / Compositional Event SystemsFunctional Reactive Programming / Compositional Event Systems
Functional Reactive Programming / Compositional Event Systems
Leonardo Borges
 
Ob1k presentation at Java.IL
Ob1k presentation at Java.ILOb1k presentation at Java.IL
Ob1k presentation at Java.IL
Eran Harel
 
Clojure: Practical functional approach on JVM
Clojure: Practical functional approach on JVMClojure: Practical functional approach on JVM
Clojure: Practical functional approach on JVM
sunng87
 
Om nom nom nom
Om nom nom nomOm nom nom nom
Om nom nom nom
Anna Pawlicka
 
2. Design patterns. part #2
2. Design patterns. part #22. Design patterns. part #2
2. Design patterns. part #2
Leonid Maslov
 
React native
React nativeReact native
React native
Vishal Dubey
 
Angular 16 – the rise of Signals
Angular 16 – the rise of SignalsAngular 16 – the rise of Signals
Angular 16 – the rise of Signals
Coding Academy
 
(map Clojure everyday-tasks)
(map Clojure everyday-tasks)(map Clojure everyday-tasks)
(map Clojure everyday-tasks)
Jacek Laskowski
 
Internationalizing react apps
Internationalizing react appsInternationalizing react apps
Internationalizing react apps
George Bukhanov
 

Similar to ClojureScript interfaces to React (20)

ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015
 
Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript
Progscon 2017: Taming the wild fronteer - Adventures in ClojurescriptProgscon 2017: Taming the wild fronteer - Adventures in Clojurescript
Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript
 
High Performance web apps in Om, React and ClojureScript
High Performance web apps in Om, React and ClojureScriptHigh Performance web apps in Om, React and ClojureScript
High Performance web apps in Om, React and ClojureScript
 
ClojureScript - Making Front-End development Fun again - John Stevenson - Cod...
ClojureScript - Making Front-End development Fun again - John Stevenson - Cod...ClojureScript - Making Front-End development Fun again - John Stevenson - Cod...
ClojureScript - Making Front-End development Fun again - John Stevenson - Cod...
 
Exploring Clojurescript
Exploring ClojurescriptExploring Clojurescript
Exploring Clojurescript
 
Front-end God Mode with Reagent and Figwheel
Front-end God Mode with Reagent and FigwheelFront-end God Mode with Reagent and Figwheel
Front-end God Mode with Reagent and Figwheel
 
Reactive, component 그리고 angular2
Reactive, component 그리고  angular2Reactive, component 그리고  angular2
Reactive, component 그리고 angular2
 
React native
React nativeReact native
React native
 
Road to react hooks
Road to react hooksRoad to react hooks
Road to react hooks
 
Ember.js - A JavaScript framework for creating ambitious web applications
Ember.js - A JavaScript framework for creating ambitious web applications  Ember.js - A JavaScript framework for creating ambitious web applications
Ember.js - A JavaScript framework for creating ambitious web applications
 
Android Support Library
Android Support LibraryAndroid Support Library
Android Support Library
 
Functional Reactive Programming / Compositional Event Systems
Functional Reactive Programming / Compositional Event SystemsFunctional Reactive Programming / Compositional Event Systems
Functional Reactive Programming / Compositional Event Systems
 
Ob1k presentation at Java.IL
Ob1k presentation at Java.ILOb1k presentation at Java.IL
Ob1k presentation at Java.IL
 
Clojure: Practical functional approach on JVM
Clojure: Practical functional approach on JVMClojure: Practical functional approach on JVM
Clojure: Practical functional approach on JVM
 
Om nom nom nom
Om nom nom nomOm nom nom nom
Om nom nom nom
 
2. Design patterns. part #2
2. Design patterns. part #22. Design patterns. part #2
2. Design patterns. part #2
 
React native
React nativeReact native
React native
 
Angular 16 – the rise of Signals
Angular 16 – the rise of SignalsAngular 16 – the rise of Signals
Angular 16 – the rise of Signals
 
(map Clojure everyday-tasks)
(map Clojure everyday-tasks)(map Clojure everyday-tasks)
(map Clojure everyday-tasks)
 
Internationalizing react apps
Internationalizing react appsInternationalizing react apps
Internationalizing react apps
 

Recently uploaded

Transform Your Communication with Cloud-Based IVR Solutions
Transform Your Communication with Cloud-Based IVR SolutionsTransform Your Communication with Cloud-Based IVR Solutions
Transform Your Communication with Cloud-Based IVR Solutions
TheSMSPoint
 
E-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian Companies
E-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian CompaniesE-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian Companies
E-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian Companies
Quickdice ERP
 
Using Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional SafetyUsing Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional Safety
Ayan Halder
 
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, FactsALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
Green Software Development
 
Neo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j - Product Vision and Knowledge Graphs - GraphSummit ParisNeo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j
 
Vitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdfVitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke
 
SWEBOK and Education at FUSE Okinawa 2024
SWEBOK and Education at FUSE Okinawa 2024SWEBOK and Education at FUSE Okinawa 2024
SWEBOK and Education at FUSE Okinawa 2024
Hironori Washizaki
 
Oracle 23c New Features For DBAs and Developers.pptx
Oracle 23c New Features For DBAs and Developers.pptxOracle 23c New Features For DBAs and Developers.pptx
Oracle 23c New Features For DBAs and Developers.pptx
Remote DBA Services
 
LORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptx
LORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptxLORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptx
LORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptx
lorraineandreiamcidl
 
Why Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise Edition
Why Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise EditionWhy Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise Edition
Why Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise Edition
Envertis Software Solutions
 
How to write a program in any programming language
How to write a program in any programming languageHow to write a program in any programming language
How to write a program in any programming language
Rakesh Kumar R
 
Atelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissancesAtelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissances
Neo4j
 
openEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain SecurityopenEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain Security
Shane Coughlan
 
SMS API Integration in Saudi Arabia| Best SMS API Service
SMS API Integration in Saudi Arabia| Best SMS API ServiceSMS API Integration in Saudi Arabia| Best SMS API Service
SMS API Integration in Saudi Arabia| Best SMS API Service
Yara Milbes
 
GraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph TechnologyGraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph Technology
Neo4j
 
E-commerce Application Development Company.pdf
E-commerce Application Development Company.pdfE-commerce Application Development Company.pdf
E-commerce Application Development Company.pdf
Hornet Dynamics
 
Artificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension FunctionsArtificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension Functions
Octavian Nadolu
 
AI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI App
AI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI AppAI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI App
AI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI App
Google
 
Graspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code AnalysisGraspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code Analysis
Aftab Hussain
 
What is Master Data Management by PiLog Group
What is Master Data Management by PiLog GroupWhat is Master Data Management by PiLog Group
What is Master Data Management by PiLog Group
aymanquadri279
 

Recently uploaded (20)

Transform Your Communication with Cloud-Based IVR Solutions
Transform Your Communication with Cloud-Based IVR SolutionsTransform Your Communication with Cloud-Based IVR Solutions
Transform Your Communication with Cloud-Based IVR Solutions
 
E-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian Companies
E-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian CompaniesE-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian Companies
E-Invoicing Implementation: A Step-by-Step Guide for Saudi Arabian Companies
 
Using Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional SafetyUsing Xen Hypervisor for Functional Safety
Using Xen Hypervisor for Functional Safety
 
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, FactsALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
 
Neo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j - Product Vision and Knowledge Graphs - GraphSummit ParisNeo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
Neo4j - Product Vision and Knowledge Graphs - GraphSummit Paris
 
Vitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdfVitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdf
 
SWEBOK and Education at FUSE Okinawa 2024
SWEBOK and Education at FUSE Okinawa 2024SWEBOK and Education at FUSE Okinawa 2024
SWEBOK and Education at FUSE Okinawa 2024
 
Oracle 23c New Features For DBAs and Developers.pptx
Oracle 23c New Features For DBAs and Developers.pptxOracle 23c New Features For DBAs and Developers.pptx
Oracle 23c New Features For DBAs and Developers.pptx
 
LORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptx
LORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptxLORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptx
LORRAINE ANDREI_LEQUIGAN_HOW TO USE WHATSAPP.pptx
 
Why Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise Edition
Why Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise EditionWhy Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise Edition
Why Choose Odoo 17 Community & How it differs from Odoo 17 Enterprise Edition
 
How to write a program in any programming language
How to write a program in any programming languageHow to write a program in any programming language
How to write a program in any programming language
 
Atelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissancesAtelier - Innover avec l’IA Générative et les graphes de connaissances
Atelier - Innover avec l’IA Générative et les graphes de connaissances
 
openEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain SecurityopenEuler Case Study - The Journey to Supply Chain Security
openEuler Case Study - The Journey to Supply Chain Security
 
SMS API Integration in Saudi Arabia| Best SMS API Service
SMS API Integration in Saudi Arabia| Best SMS API ServiceSMS API Integration in Saudi Arabia| Best SMS API Service
SMS API Integration in Saudi Arabia| Best SMS API Service
 
GraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph TechnologyGraphSummit Paris - The art of the possible with Graph Technology
GraphSummit Paris - The art of the possible with Graph Technology
 
E-commerce Application Development Company.pdf
E-commerce Application Development Company.pdfE-commerce Application Development Company.pdf
E-commerce Application Development Company.pdf
 
Artificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension FunctionsArtificia Intellicence and XPath Extension Functions
Artificia Intellicence and XPath Extension Functions
 
AI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI App
AI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI AppAI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI App
AI Fusion Buddy Review: Brand New, Groundbreaking Gemini-Powered AI App
 
Graspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code AnalysisGraspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code Analysis
 
What is Master Data Management by PiLog Group
What is Master Data Management by PiLog GroupWhat is Master Data Management by PiLog Group
What is Master Data Management by PiLog Group
 

ClojureScript interfaces to React

  • 1. ClojureScript interfaces to React Michiel Borkent @borkdude Øredev, November 6th 2014
  • 2. Michiel Borkent (@borkdude) ● Clojure(Script) developer at ● Clojure since 2009 ● Former lecturer, taught Clojure
  • 3. Full Clojure stack example @ Finalist Commercial app. Fairly complex UI ● Menu: 2 "pages" Page 1: Dashboard. Create new or select existing entity to work on. Then: ● Wizard 1 ○ Step 1..5 ○ Each step has a component ● Wizard 1 - Step2 ○ Wizard 2 ■ Step 1' ■ Step 2'
  • 4. Full Clojure stack examples @ Finalist Step 2 of inner wizard: ● Three dependent dropdowns + backing ajax calls ● Crud table of added items + option to remove ● When done: create something based on all of this on server and reload entire "model" based on what server says Because of React + Om we didn't have to think about updating DOM performantly or keeping "model" up to date.
  • 5. Agenda ● What is React? ● Om ● Reagent
  • 7. React ● Developed by Facebook ● Helps building reusable and composable UI components ● Unidirectional Data Flow ● Less need for re-rendering logic ● Leverages virtual DOM for performance ● Can render on server to make apps crawlable
  • 8. /** @jsx React.DOM */ var Counter = React.createClass({ getInitialState: function() { return {counter: this.props.initialCount}; }, inc: function() { this.setState({counter: this.state.counter + 1}); }, render: function() { return <div> {this.state.counter} <button onClick={this.inc}>x</button> </div>; } }); React.renderComponent(<Counter initialCount={10}/>, document.body);
  • 10. Prior knowledge (def my-atom (atom 0)) @my-atom ;; 0 (reset! my-atom 1) (reset! my-atom (inc @my-atom)) ;; bad idiom (swap! my-atom (fn [old-value] (inc old-value))) (swap! my-atom inc) ;; same @my-atom ;; 4
  • 11. Before React: manual DOM edits (add-watch greeting-form :form-change-key (fn [k r o n] (dispatch/fire :form-change {:old o :new n}))) (dispatch/react-to #{:form-change} (fn [_ m] (doseq [s (form-fields-status m)] (render-form-field s)) (render-button [(-> m :old :status) (-> m :new :status)] ))) source: http://clojurescriptone.com/documentation.html
  • 12. ClojureScript interfaces Quiescent - Luke vanderHart Om - David Nolen Reagent (was: Cloact) - Dan Holmsand
  • 13. React + ClojureScript Both Om and Reagent leverage: ● immutability for faster comparison in shouldComponentUpdate ● Fewer redraws by batching updates with requestAnimationFrame
  • 14. Om ● Opinionated library by David Nolen ● One atom for app state ● Props: narrowed scope of app state (cursor) (def app-state (atom {:counter1 {:count 10} :counter2 {:count 11}})) (defn main [app owner] (om/component (dom/div nil (om/build counter (:counter1 app)) (om/build counter (:counter2 app)))))
  • 15. Om ● Communication between components via ○ setting init-state / state (parent -> child) ○ callbacks (child -> parent) ○ app-state ○ core.async ● Explicit hooks into React lifecycle via ClojureScript protocols ● Follows React semantics closely (e.g. local state changes cause re-rendering)
  • 16. (def app-state (atom {:counter 10})) (defn app-state-counter [app owner] (reify om/IRender (render [_] (dom/div nil (:counter app) (dom/button #js {:onClick #(om/transact! app :counter inc)} "x"))))) (om/root app-state-counter app-state {:target (. js/document (getElementById "app"))})
  • 18. Some catches ● Large vocabulary around cursors: app(-state), owner, build, cursors, ref-cursors, root, update!, update-state!, transact!, opts ● Cursor behaves differently depending on lifecycle ● Strong correspondence between component tree structure and app state structure (ref-cursors are supposed to solve this) ● Heavy use of callbacks or core.async to make components reusable (should not rely on app-state) ● Omission of #js reader literal, :className instead of :class, or nil if no attributes used, fails silently or cryptic error messages
  • 20. Reagent Uses RAtoms for state management Components are 'just functions'™ that ● must return something renderable by React ● can deref RAtom(s) ● can accept props as args ● may return a closure, useful for setting up initial state
  • 21. Reagent ● Components should be called like [component args] instead of (component args) ● Components are re-rendered when ○ props (args) change ○ referred RAtoms change ● Hook into React lifecycle via metadata on component functions (def component (with-meta (fn [x] [:p "Hello " x ", it is " (:day @time-state)]) {:component-will-mount #(println "called before mounting") :component-did-update #(js/alert "called after updating")} ))
  • 22. (def count-state (atom 10)) (defn counter [] [:div @count-state [:button {:on-click #(swap! count-state inc)} "x"]]) (reagent/render-component [counter] (js/document.getElementById "app")) RAtom
  • 23. (defn local-counter [start-value] (let [count-state (atom start-value)] (fn [] [:div @count-state [:button {:on-click #(swap! count-state inc)} "x"]]))) (reagent/render-component [local-counter 10] (js/document.getElementById "app")) local RAtom
  • 24. CRUD!
  • 25. (def animals-state (atom #{})) (go (let [response (<! (http/get "/animals")) data (:body response)] (reset! animals-state (set data)))) RAtom with set containing animal hash-maps (... {:id 2, :type :animal, :name "Yellow-backed duiker", :species "Cephalophus silvicultor"} {:id 1, :type :animal, :name "Painted-snipe", :species "Rostratulidae"}
  • 26. Render all animals from state (defn animals [] [:div [:table.table.table-striped [:thead [:tr [:th "Name"] [:th "Species"] [:th ""] [:th ""]]] [:tbody (map (fn [a] ^{:key (str "animal-row-" (:id a))} [animal-row a]) (sort-by :name @animals-state)) [animal-form]]]]) a row component for each animal form to create new animal key needed for React to keep track of rows
  • 27.
  • 28. (defn animal-row [a] (let [row-state (atom {:editing? false :name (:name a) :species (:species a)}) current-animal (fn [] (assoc a :name (:name @row-state) :species (:species @row-state)))] (fn [] [:tr [:td [editable-input row-state :name]] [:td [editable-input row-state :species]] [:td [:button.btn.btn-primary.pull-right {:disabled (not (input-valid? row-state)) :onClick (fn [] (when (:editing? @row-state) (update-animal! (current-animal))) (swap! row-state update-in [:editing?] not))} (if (:editing? @row-state) "Save" "Edit")]] [:td [:button.btn.pull-right.btn-danger {:onClick #(remove-animal! (current-animal))} "u00D7"]]])))
  • 29. (defn field-input-handler "Returns a handler that updates value in atom map, under key, with value from onChange event" [atom key] (fn [e] (swap! atom assoc key (.. e -target -value)))) (defn input-valid? [atom] (and (seq (-> @atom :name)) (seq (-> @atom :species)))) (defn editable-input [atom key] (if (:editing? @atom) [:input {:type "text" :value (get @atom key) :onChange (field-input-handler atom key)}] [:p (get @atom key)]))
  • 30. (defn remove-animal! [a] (go (let [response (<! (http/delete (str "/animals/" (:id a))))] (if (= (:status response) 200) (swap! animals-state remove-by-id (:id a)))))) (defn update-animal! [a] (go (let [response (<! (http/put (str "/animals/" (:id a)) {:edn-params a})) updated-animal (:body response)] (swap! animals-state (fn [old-state] (conj (remove-by-id old-state (:id a)) updated-animal)))))) replace updated animal retrieved from server if server says: "OK!", remove animal from CRUD table
  • 31. Live demo If you want to try yourself. Code and slides at: https://github.com/borkdude/oredev2014
  • 32. My experience with Om and Reagent ● Both awesome ● Added value to React ● Om encourages snapshot-able apps but: ○ surprises ○ large vocabulary ● Reagent ○ easy to learn and use ○ readable