The Case for React.js and ClojureScript

Post on 28-Aug-2014

1143 Views

Category:

Software

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

Sonian Tech Talk presentation given on may 2, 2014. http://murilopereira.com/the-case-for-reactjs-and-clojurescript/

Transcript

The Case for

React.js andClojureScript

Murilo Pereira

@mpereira

May 2, 2014

Problem

Building UIs isdifficult.

Modern Web UIsvisual representations of data changing over timerespond to asynchronous user eventstransition both the underlying data and itself to new states

"Data changing over time is theroot of all evil."

Incidental ComplexityJavaScript isn't DOM is stateful

reactive

What if the JavaScript DOMAPI was reactive?

function tweetScore(tweet) { return(tweet.favorites_count + tweet.retweets_count);}

function compareTweetsByScore(a, b) { return(tweetScore(b) - tweetScore(a));}

function renderApplication(tweets) { return(document.dom.ul( { class: 'tweets' }, tweets .sort(compareTweetsByScore) .slice(0, 5) .map(function(tweet) { return(document.dom.li({ class: 'tweet' }, tweet.text); }) ));}

var tweets = fetchTweets({ username: 'mpereira' }, { limit: 20 });document.dom.render(renderApplication(tweets), document.body);

Possible solution: Data binding

Data BindingObservablesComputed properties

Backbone, Ember, Meteor, et al.

Contemporary data binding isnot simple.

SimpleNot to be mistaken for "easy"

Easiness = Familiarity (subjective)

Simplicity = "Does/is one thing" (objective)

Data BindingApplication logic entangled with observablesForces us to compose our programs with frameworkconstructs instead of language constructs (functions and datastructures)

"How often are you fighting theframework?"

Dirty-checking (Angular)Also susceptible to the problems of data binding.

https://docs.angularjs.org/guide/concepts

Complex

Even with shortcomings it'sstill possible to build complex,

modern UIs usingcontemporary MVC

frameworks.

"We can create precisely thesame programs we're creating

right now with drasticallysimpler tools."

Rich Hickey

A different solution to the sameproblem.

React.js

React.jsLibrary for creating UIsRenders the DOM and responds to user eventsCan be thought of as the V in MVC

Remember our utopic examplea few slides back?

function tweetScore(tweet) { return(tweet.favorites_count + tweet.retweets_count);}

function compareTweetsByScore(a, b) { return(tweetScore(b) - tweetScore(a));}

function renderApplication(tweets) { return(document.dom.ul( { class: 'tweets' }, tweets .sort(compareTweetsByScore) .slice(0, 5) .map(function(tweet) { return(document.dom.li({ class: 'tweet' }, tweet.text); }) ));}

var tweets = fetchTweets({ username: 'mpereira' }, { limit: 20 });document.dom.render(renderApplication(tweets), document.body);

It's actually valid React.js code

function tweetScore(tweet) { return(tweet.favorites_count + tweet.retweets_count);}

function compareTweetsByScore(a, b) { return(tweetScore(b) - tweetScore(a));}

function renderApplication(tweets) { return(React.DOM.ul( { className: 'tweets' }, tweets .sort(compareTweetsByScore) .slice(0, 5) .map(function(tweet) { return(React.DOM.li({ className: 'tweet' }, tweet.text); }) ));}

var tweets = fetchTweets({ username: 'mpereira' }, { limit: 20 });React.renderComponent(renderApplication(tweets), document.body);

React gives us a minimallyleaky abstraction for a reactiveJavaScript/DOM environment.

Data

Component

DOM

Model

View

DOM

M3

V2

DOM

M2 M4 M5M1

V1 V3

Data

C3

DOM

C4C2 C5C1

Components

ComponentsIdempotent functions that describe your

UI at any point in time.

component(data) = VDOM

component(data_1) = VDOM_1

*user input changes data from data_1 to data_2*

component(data_2) = VDOM_2diffVDOMs(VDOM_1, VDOM_2) = diffDOMOperations(diff) = operations

applyDOMOperations(operations, document.body)

Best part? You don't even haveto worry about this. Just build

components.

Every place data is displayed isguaranteed to be up-to-date. 

No need for KVO or markingHTML templates withframework directives.

Frees the programmer fromdoing manual, explicit DOM

operations.

But what about theperformance?

Isn't diffing VDOMs slow?

Why have VDOMs if thebrowser already has a DOM?

The DOM is slow.

The DOM is slowQuerying may require tree traversalMutations trigger viewport reflows, relayouts, repaints (CSSengine, etc.)Can also invalidate caches, requiring the entire DOM to bereconstructed on the viewport

Having in-memoryrepresentations of the DOM

allows React to have extremelyfast UIs.

Virtual DOM (VDOM)Allows for components to have a declarative APIPerforms the minimum amount of actual DOM operationsthrough computing diffsHandles DOM operations for you

"Performance isn't the [main]goal of the VDOM, but if you'reworried with performance,

most workloads are as fast orfaster [than the MVC

alternatives] out of the box."Pete Hunt

Components

Components allow you toexpress your program in thelanguage of your problem

domain.

Rather than on the language ofa particular framework.

Bill O'Reilly

Tide comes in, tide goes out.You can't explain that!

Top Tweets

Just had #breakfast.

@troll yes, definitely plan onthat.

pic.twitter.com/asd23 #selfie#instagram

Good# morning.

Bill O'Reilly

Top Tweets

Tide comes in, tide goes out.You can't explain that! #tides

Just had #breakfast.

@troll yes, definitely plan onthat.

pic.twitter.com/asd23 #selfie#instagram

Good# morning.

Header

Profile

Tweets

Top Tweets

var Profile = React.createClass({ render: function() { return(React.DOM.div(null, [ React.DOM.img(null, this.props.user.image), React.DOM.p(null, this.props.user.name) ]); }});

var Tweets = React.createClass({ render: function() { return(React.DOM.ul(null, this.props.tweets.map(function(tweet) { return(React.DOM.li(null, tweet.text)); }); }});

var TopTweets = React.createClass({ render: function() { return(React.DOM.div(null, [ React.DOM.h1(null, 'Top Tweets'), Profile({ user: this.props.user }), Tweets({ tweets: this.props.user.tweets }) ]); }});

React.renderComponent(TopTweets({ user: user }), document.body);

var Profile = React.createClass({ render: function() { return( <div> <img href={this.props.user.image} /> <p>{this.props.user.name}</p> </div> ); }});

var Tweets = React.createClass({ render: function() { return( <ul> {this.props.tweets.map(function(tweet) { return(<li>tweet.text</li>); })}; </ul> ); }});

var TopTweets = React.createClass({ render: function() { return( <div> <h1>Top Tweets</h1> <Profile user={this.props.user} /> <Tweets tweets={this.props.user.tweets} /> </div> ); }

TopTweets(data) = Header() + Profile(data_1) + Tweets(data_2)

Components are reusable andcomposable declarative

representations of your UI.

CollateralBenefits

Collateral BenefitsRender the application on the server (node.js, Java 8'sNashhorn, etc.)UI testability for freeNo templates!

React.js takeawaysDeclarative, fast UIsExpress your programs in the language of your problemdomain

ClojureScript

ProblemJavaScript sucks

We need JavaScript

JavaScript sucksNo integersNo module systemVerbose syntaxConfusing, inconsistent equality operatorsConfusing, inconsistent automatic operator conversionsLack of block scopeNon-uniform iteratorsGlobal variables by defaultNaNthisNo macros (yet...)etc.

We Need JavaScriptRuntime is everywhereRuntime is improving (Web Sockets, geo-location, FS API, RAF,push notifications, WebRTC, WebGL, SVG, Canvas, WebWorkers, IndexedDB, etc.)

Build better languages on topof JavaScript.

Compilers!Lots of them already existOnly a few bring significant improvements

Popular ones

CoffeeScript: mostly syntax sugarTypeScript: typed superset of JavaScript. Brings type checking,compile time errors

ClojureScript

ClojureScript is a Clojurecompiler that targets

JavaScript.

Why ClojureScript?Why Clojure?Why LISP?

Clojure is just a betterlanguage.

Number of daysspent designingthe language v1

JavaScript Clojure

ClojureScriptLISPSTMRuntime polymorphismThe REPLFunctional programmingImmutable data structuresUniform API over immutable data structuresMacrosLazy sequencesDestructuringState VS Identityetc.

core.async(go (try (let [tweets (<? (get-tweets-for "swannodette")) first-url (<? (expand-url (first (parse-urls tweets)))) response (<? (http-get first-url))] (. js/console (log "Most recent link text:" response))) (catch js/Error e (. js/console (error "Error with the twitterverse:" e)))))

Asynchronous Error Handling

The possibility of havingaccess to the power of Clojurein the browser is immensely

valuable.

ValueTo programmers, who will be able to build better programs, with

less bugs, faster.

To the people and companies who will benefit from thoseprograms.

The developer experience hasimproved significantly.

Developer ExperienceSource mapsEasily reproducible tutorialsBrowser-connected in-editor REPLsFast compilation cyclesCompatible libraries

Recommend you to check itout

(but you probably have, already)

Om

ClojureScript interface to React.

"Because of immutable dataOm can deliver even better

performance than React out ofthe box."

David Nolen

30-40X faster than JS MVCs nothing to do with ClojureScript. Ditch stateful objects, ditch events. Be declarative. Immutability. That's it.5:39 AM - 15 Dec 2013

David Nolen @swannodette

Follow

41 RETWEETS 39 FAVORITES

???

ClojureScriptCompiled, slower than hand-written JavaScriptUses immutable data structures, slower than JavaScript datastructures

And yet

Om's performance beats thatof most JavaScript MVC

frameworks

"Ideas have fundamentalperformance properties."

Pete Hunt

Immutable data structuresmake React's diffing algorithm

really smart.

Takeaways

"Ideas have fundamentalperformance properties."

"Don't trade simplicity forfamiliarity."

And  .give it five minutes

Thanks! @mpereira

top related