class: center, middle # Functional UI, Composable Components and Unidirectional immutable data --- # The Beginning ## Static HTML, No JS ??? First there was pure, perfect static model: Just rendering in declarative way. Things were easy to understand just by taking a glance. But there were no inputs. Just static texts as values and attributes. --- # The Need for Dynamic Views ## Using JS to change the DOM ??? Need for dynamic changes without server change. In time we got Mootools and jQuery. Now we had ways to traverse, update and manipulate the DOM with ease. Didn’t have much models or any good way in the code to represent what state we have in the DOM --- # The Need for Structural Views ## More Responsibility to JS ??? As time went and javascript got more and more popular and as we moved to thicker clients and more logic in the browser, we got things as Backbone. We had models and some javascript views, but still driven by massive blob of a side-effect that is the stateful DOM. It’s not necessarily easy to predict the current state of the DOM, even if we have some representation. --- # The De-tour Through Increased Power of Models ## Hard-linking Models and DOM ??? - We also got things like Knockout, and later Angular, Ember and such. We could bind a model to a view. The problem is, you very rarely have a model which you can bind directly to a view, so you can have view models, or other representations, but then you’d have to either listen for propagating changes and having weird hacks for propagating changes in the object models doing dirty bit checking or some other polling. And you still have this built up state that’s not too easily reproducible or predictable. We still don’t have the same static mental model as in the pure HTML days - "HTML should be just a projection of app state, not a source of truth!" - Daniel Steigerwald --- # Real Power of Programming ## Moving Views All The Way To JS ??? The next iteration for views is taking the back to a static model and predictable views. Instead of taking the step of moving more JS into the markup, we do the opposite and move views entirely into a representation in a declarative manner of writing composable views, just as with HTML - but with extended functionality. Instead of having a powerful programming language in a less powerful representation language, we move the representation to the programming language. --- # Building Representation of Views in JS ## Advantages Of Using React and it's Virtual DOM ??? We can write UI components in an expressive manner in the same way we would in a markup language, but we'd do it in a programming language. The conceptual distance isn't big, it's just different languages. We will see that there are steps to take for making the languages look more similar, but it's not neccessary. It's more conceptual than anything. We will see more on what the Virtual DOM is, but for now, it's not too important. Just think of it as an abstraction of the DOM which allows us to write performant view representations in code. --- # Static Mental Model Just Like Good Old HTML ??? Built for changes over time, and between each change it essentially does a refresh, but has a internal representation of the DOM which it's diffed gainst and the actual changes only occurs when the new generated virtual DOM diverges from the old. --- # React.js ```js var Hello = React.createClass({ render: function () { return React.DOM.h1({}, 'Hello, world!'); } }); // Need to create element from class React.render(React.createElement(Hello), document.body); ``` ??? Many, or most, of you might have seen React before, but here is an example, in plain old JS. Or we can make a component of it, which we can re-use in different settings and compose. In the latest version of React (0.13), they have transition into using ES6 classes, but you could also use module patterns or ES3 classes. --- # Passing props ```js var Hello = React.createClass({ render: function () { return React.DOM.h1({}, 'Hello, ' + this.props.user.name + '!'); } }); var myProps = { user: { name: 'Hank Pym' } }; // Need to create element from class var element = React.createElement(Hello, myProps); React.render(element, document.body); ``` ??? We can also pass properties to the components. Much like attributes and children of regular HTML, but instead of being restricted to a protocol of only strings, we can pass objects and more advanced constructs. --- # Syntactic Sugar: JSX ```js React.render(
Hello, world!
, document.body); // Translates to React.render( React.createElement('h1', {}, 'Hello, world!'), document.body); ``` ??? In React 0.12.0, they changed from rendering components into rendering Elements based on classes. This to move towards ES6 "Classes". This means in vanilla React it can be somewhat verbose syntax for non-JSX, allthough it is still possible. We'll see later in this workshop how we can make working with vanilla JS better. JSX is a transpile-to-JS language, with a very small transpilation distance. --- # Previous example with JSX ```js var Hello = React.createClass({ render: function () { return
Hello, {this.props.user.name}!
; } }); var myProps = { user: { name: 'Hank Pym' } }; React.render(
, document.body); ``` --- # Part 1 Assignments: Creating Components 1. Test out [the playground](http://omniscientjs.github.io/workshop) (1) 2. Making Basic Components (2) 3. Passing Properties (3) 4. Transforming input props (4) --- # Composability Through Components ```js var Greeting = React.createClass({ render: function () { return (
Hello, {this.props.user.name}!
Here, have some chimichangas!
); } }); var myProps = { user: { name: 'Wade Wilson' } }; React.render(
, document.body); ``` ??? Just rendering a HTML document isn't much of an application, and we could just use HTML if we weren't making a more complex application. We need to combine different components for making larger structures. --- # Multiple components ```js var Hello = React.createClass({ render: function () { return
Hello, {this.props.username}!
; } }); var Greeting = React.createClass({ render: function () { return (
You look like Spider-man!
); } }); var myProps = { user: { name: 'Wade Wilson' } }; React.render(
, document.body); ``` --- # Composing with children ```js var Hello = React.createClass({ render: function () { return
Hello, {this.props.children}!
; } }); var Greeting = React.createClass({ render: function () { return (
{this.props.user.name}
Wheres Pandapool?
); } }); var myProps = { user: { name: 'Wade Wilson' } }; React.render(
, document.body); ``` --- # Functional Patterns for UI ```js var h1 = input =>
{input}
; var em = input =>
{input}
; var compose = (a, b) => (input => a(b(input))); var italicH1 = compose(h1, em); var Greeting = React.createClass({ render: function () { return (
{italicH1(this.props.name)}
You got some vibranium?
); } }); React.render(
, document.body); ``` --- # Part 1: Assignments 1. Composing Simple Components (5) 2. Composing Components Through Children (6) --- # DOM is a Side-Effect ## Abstract Side-Effects to Edges of Communication Graph ![Data flow](./dataflow-edge-sideeffects.png) ??? We don't want to handle the communication to the DOM our self. Firstly, integration tests to the DOM is a pain, it is slow and it is a huge state which is built through different operations which is easy to loose track off. We can avoid that by "refreshing" the view entirly and only showing the latest changes to the UI. --- # Virtual DOM ## What Allows Us To Write Smart DOM Representations ??? - So the Virtual DOM, which React implements, helps us abstracting the DOM. We don't have to handle the DOM our self. Important part however, is that the distance between the DOM and the Virtual DOM isn't big. It's not like Hibernate and SQL. --- # In-memory Representation of the DOM ## Only Actually Render When Output Changes ??? - The Virtual DOM works by having a in-memory representation of the DOM and on update / refresh it does a fast diff between the new generated virtual DOM and the current internal DOM, and it only updates to the actual DOM the thing that is changed. --- # Re-render For Every Change ```js var Name = React.createClass({ render: function () { return
{this.props.name}
; } }); React.render(
, document.body); // No actual DOM operations! React.render(
, document.body); React.render(
, document.body); // Will change React.render(
, document.body); ``` ??? - A normal React pattern is just to refresh the views every time. So re-render the views with new input and cause different output. As mentioned; the output is diffed against the in-memory DOM. --- # Heads Up! ## Might Create Increased Work For the GC ## Can create a lot of objects that should be thrown away by the GC ??? - react is not a silver bullet - atom had to move away from it - to fragmented painting, to much gc on changes --- # Part 1: Assignments 1. Render two times and see that only the second will be visible. (7) 2. Render twice to update view using `setTimeout`. (8) 3. Render a clock using `setInterval`. (9) ??? Setup: - react component state change causes re-render - state gets out of hand - opens many new posibilities - can still fuck things up - to recreate the mental model from html - borrow concepts from functional programming - makes reasoning about or user intercaes easier - easier to make less error prone system --- # Functional paradigm ## The mental model ??? - why strive for principles of functional programming? - in general we believe it makes reasoning about you programs easier - we also believe its helful for reasoning about your views - easier mental model - modular programs - easier to write - easier to test - decompose problems into parts - useful in terms of composability, especially when it comes to your views, which well see later --- # Pure functions & Referential transparency ## Code without side-effects! ```js var square = function (x) { return x * x; }; ``` ??? - Given the same input, the program has the same effects and outputs - write code that functions that have predictable output, given some input - dont depent on global state - testability - predictable functions -> predictable system --- # Pure functions & Referential transparency ## "An expresssion is referentially transparent if it can be replaced with its value without changing the behavior of the program." ```js foo(x) + foo(x) ``` vs ```js 2 * foo(x) ``` ??? - a properties of parts of computer programs - or said in another way; indicates that you can determine the result of applying that function only by looking at the values of its arguments - in imperative languages, you can't nescessarily - in mathematics you can - makes code easier to test - easier to reason about, can swap a function call with its value - memoized --- # Higher order functions ## Functions as values ## Functions can take functions as arguments ## Functions can return functions ??? - the glue - Primary building blocks --- # Functions that return functions ```js var adder = function (add) { return function (x) { return add + x; }; }; var add2 = adder(2); add2(4); // 6 ``` ??? - function that creates other functions - the inner function is said to close over `add` - available after the outer function has returned - we create a function that always return add2 --- # Function that takes another function as an argument ## From one representation to another ```js var list = [1, 2, 3]; var square = function (n) { return n * n; }; it('squares numbers', function () { list.map(square).should.eql([1, 4, 9]) }); ``` ??? - like a physical map, go from one place to another - maps one representation into another - transforms the dataset into another --- # Function that takes another function as an argument ## Filters out items of list ```js var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; var isFizzOrBuzz = function (n) { return n % 5 == 0 || n % 3 == 0; }; it('keeps fizzbuzz numbers', function () { numbers.filter(isFizzOrBuzz).should.eql([3, 5, 6, 9, 10]) }); ``` --- # Function that takes another function as an argument ## Reduces items of a list into an accumulator ```js var numbers = [1, 2, 3, 4, 5]; var multiply = function (acc, n) { return acc * n; } it('multiplies numbers', function () { numbers.reduce(multiply, 1).should.equal(120); }); ``` --- # Data transformation ```js var episodes = [ { name: "Cartman Gets an Anal Probe" }, { name: "Weight Gain 4000" }, { name: "Volcano" }, { name: "Big Gay Al's Big Gay Boat Ride" }, { name: "An Elephant Makes Love to a Pig" }, { name: "Death" }, { name: "Pinkeye" } ]; function asName (obj) { return obj.name; } function nth (list, i) { return list[i]; } it('maps episodes => name', function () { nth(episodes.map(asName), 0).should.equal("Cartman Gets an Anal Probe"); nth(episodes.map(asName), 1).should.equal("Weight Gain 4000"); }); ``` ??? - all of these are examples of higher order functions - you pass functions that are used to perform operations on data - keep their result - operate on lists - what programming is about, chrunching data, transforming data from one representation to another - interesting properties: pure functions, no side effects, immutable structures - why pure/immutable? not to have side effects - make sure others cannot change what is your starting point/basis --- # Part 2: Assignments 1. Higher order functions (10) 2. Write a recursive function that sums the numbers of a list (11) ??? - While some operations e.g. map, filter, reduce return new lists, the content of these lists may well be references to objects you started out with - need to be aware - not everything is immutable in js as of today --- # Immutable data ??? - another important aspect of functional programming - also makes things easier to reason about - essentially means when someone changes data, theyre given a copy - don't have to worry about others changing your data - perfect for passing as part of an event - not everything is immutable in js --- # Object.freeze(someObject); ??? - Object.freeze() makes it immutable - "Can't add property
, object is not extensible"" - not efficient - cant update an object without copying all values to a new object - how can we copy it? - can we copy everything all the time? - the two are almost exaclty the same - doesnt this use twice the space? --- # clojure ```clj (def user {:firstname "Steve"}) (def modified-user (assoc user :lastname "Rogers")) (= user modified-user) // false ``` ??? - some languages have immutable data by default! - youre forced to keep the output of your operations - this update can be fast - data can be shared between these to objects, because data is never chagned, its immutable - well see how a similar effect can be reached in javascript as well in a bit --- # Some things are immutable in most languages! ## string ```js var name = 'bob'; it('returns new strings', function () { var names = name + ' & alice'; names.should.equal('bob & alice'); name.should.equal('bob'); }); ``` ??? - strings - primitive datatypes, ints --- # Js is immutable ## concat() ```js var list = [1, 2, 3] var res = list.concat(42) // [1, 2, 3, 42] list // [1, 2, 3] ``` ??? --- # But js is confused ## push() ```js var list = [1, 2, 3] list.push(42) // 4 list // [1, 2, 3, 42] ``` ??? - push, mutating => why? - you push 42, you get 4 back, you get the length back? --- # Immutable data alternatives for js ## [ki](http://ki-lang.org) ## [mori](https://github.com/swannodette/mori) ## [clojurescript](http://clojure.org/clojurescript) ??? - there are alternatives for js - and some of these are awesome - by super smart people - but no one is really javascript idiomatic --- # Immutable.js ## Facebook ## Immutable data strcutures for js ## Idiomatic javascript api ??? - guy at facebook, lee byron - immutable structures for js - idiomatic: e.g. treat objects like you otherwise treat objects in javascript - you have access to the same operations --- # Immutable.js ## List - push() ```js var List = Immutable.List; var initial = List([1, 2]); var modified = initial.push(3); initial // 1, 2 modified // 1, 2, 3 initial === modified // false ``` ??? - because data is immutable, data never changes, data can be shared - compared to freeze, this implementation can be fast - sub trees in the larger structure can share information - persistent data structures - share structures --- # Immutable.js ## List - indexOf() ```js List.of(10, 20, 30, 40, 50).indexOf(30); // 2 ``` --- # Immutable.js ## List - remove() ```js var initial = List.of(2, 4, 6, 8); var modified = initial.remove(2); modified // 2, 4, 8 initial === modified // false ``` ??? - which even js couldnt do.. --- # Immutable.js ## Map - get() / set() ```js var Map = Immutable.Map; var map = Map({ "key": "value" }); map.get('key'); // value var modified = map.set('key', 'new value'); // { "key": "new value" } map === modified // false ``` --- # Immutable.js ## Map - complex keys ```js var initial = Map().set(List.of(1), 'list-of-one'); initial.get(List.of(1)); // list-of-one ``` --- # Immutable.js ## Map - merge ```js var first = Map({ firstname: 'Steve' }); var last = Map({ lastname: 'Rogers' }); var merged = first.merge(last); merged.toJS() // { firstname: 'Steve', lastname: 'Rogers' } ``` --- # Immutable.js ## setIn() / toJS() ```js var data = Immutable.fromJS({ some: { structure: [1, 2, 3] } }); data.getIn(['some', 'structure']) // Immutable.List([1, 2, 3]) var updated = data.setIn(['some', 'structure', '0'], 42); updated.toJS(); // { some: { structure: [42, 2, 3 ] } } data.toJS(); // { some: { structure: [1, 2, 3 ] } } data === updated // false ``` ??? gotcha: hva om man setter inn enn VANLIG liste, og ikke en immutable én --- # Immutable.js ## debugging ```js updated.inspect(); // "Map { some: Map { structure: List [ 42, 2, 3 ] } }" ``` --- # Part 2: Assignments 1. range - create a list with 100 items (12) 2. map - map over the numbers to triple every number (12) 3. filter - filter out/removes every odd number (12) 4. reduce - reduce the numbers to find their sum (12) 5. advanced: implement curry() in js (13) ??? --- # Curry ```js var add = function (a, b) { return a + b }; var addCurried = curry(add); addCurried(2)(6); // 8 ``` --- # Cursors ```js var map = Map({ "some": { "where": { ... } } }); var cursor = Cursor.from(map, ['some', 'where']); ``` ??? - another concept of functional programming, similar to functional lenses - pointers into a data structure - cursor knows its path in the structure - get a value out of it, - or operate on the value --- # Cursors example ```js var data = Immutable.Map({ show: 'South Park', episodes: [ { name: "Cartman Gets an Anal Probe" }, { name: "Weight Gain 400" }, { name: "Volcano" }, { name: "Big Gay Al's Big Gay Boat Ride" }, { name: "An Elephant Makes Love to a Pig" }, ] }); var episodes = Cursor.from(data, ['episodes']); var updatedEpisode = episodes.updateIn([2, 'name'], function (previousName) { return previousName + '0'; }); ``` ??? - isolate actions agains separate parts of a structure in an application - pass a reference on to others - is much like a view of the data - in terms of components; this is useful with react components - a component "owns" a piece of state - can also listen for when the data of a cursor changes - which we'll see in a bit, but first some assignments --- # Part 2: Assignments 1. Create a cursor (14) 2. Update a cursor (14) 3. Show that a cursor is immutable (14) 4. Show that a cursors callback is called when the cursor is updated (14) 5. Advanced: Create a cursor, and an accompanying function that when called will always return the most recent value of the cursor (14) ??? - we can pass object references as props like we've already seen - but, what happens if one component mutates the value of a reference? - another component might have its props changed - tighlty couples the two components, horizontal coupling - slippery slope; no longer purity, no longer easily testable, no longer advantages of concurrency - React 13 will freeze props. Can pass immutable props? yes, but you cant update them. - since cursors only pass references to the data, and not the data it self - we can actually swap the pars of the structure that the cursor points to - when the cursor is updated - can have ONE structure, outside the components - no one refers to the structure directly - prevents horizontal communicaiton - all components get their data from the top, as input, like arguments --- # immstruct ## cursors ## updates the structure ## triggers an event ??? - cursors can update a piece in a structure, but returns the new structure - abstraction to update the structure when a piece changes - without affecting the other parts of the tree - listen for changes! - super easy to re-render on swap --- # immstruct example ```js var data = immstruct({ something: 'initial', another: 'part' }); data.on('swap', function (newData, oldData, path) { console.log( newData.toJS(), // { something: "updated", another: 'part' } oldData.toJS(), // { something: "initial", another: 'part' } path) // ['something'] }); data.cursor('something').update(function (oldValue) { return 'updated'; }); ``` ??? - make a change - do something when the structure changes - resfresh of the data - isnt that a perfect fit with react - refreshes the view when you rerender - you can rerender the whole thing --- # Part 2: Assignments 1. Recreate the `Hello` component that greets a name - make it re-render on swap, and change the cursor (15) 2. Create `Counter` component with a button that shows the number of times its been clicked (16) 3. Create a `Clock` component that re-renders every time the clock updates (17) ??? - Alright! Rerender all the things? - Is that smart? - React is clever, and super fast - But we have unnescessary updates, where data does not change - we re-render everything all the time - But can we do even better! --- # React's shouldComponentUpdate ## Override the function to tell react when a rerender is not nescessary ![Faded Data flow](./flow_faded.svg) ??? - A react performance optimization - Tell a component when it needs to render - Can pass it as a mixin to components --- # Mixins ```js var Component = React.createClass({ mixins: [], render: function () { return
; } }); ``` --- # shouldComponentUpdate ```js var alwaysRerender = { shouldComponentUpdate: function () { return true; } }; React.createClass({ mixins: [alwaysRerender], render: function () { return
; } }); ``` --- # Part 3: Assignments 1. Create a component that only renders the first time! And never re-renderes again on new React.render() calls (18) 2. Write your own mixin that only rerenders when your component is passed odd numbers (19) 3. Implement `shouldComponentUpdate` that works with immutable.js data structures (20) ??? - and you might be thinking: is not should component update a perfect fit for immutable datastructures? - instead of deep equaling all arguments to check if theyve changed, and we need to re-render --- # Omniscient.js ## React + Immutable + Syntactic Sugar ??? Omniscient isn't more than the principles which we have covered so far. You can use React in a way that is not referentially transparent, and pure components, and Omniscient is a really small library built on top of Omniscient which encourages functional principals to React. --- # A Default `shouldComponentUpdate` ## Smart Implementation That Checks For Immutable Data and Cursors ??? Omniscients comes with a default implementation of `shouldComponentUpdate` which is smart and checks for cursors and immutable data structures. The `shouldComponentUpdate` is designed to do as little work as possible and exits early, doing minimal work when one uses immutable data or cursors. --- # Accessible `shouldComponentUpdate` ```js var omniscient = require('omniscient'); var shouldUpdateMixin = { shouldComponentUpdate: omniscient.shouldComponentUpdate }; var ImmutableComponent = React.createClass({ mixins: [shouldUpdateMixin], render: function () { return
{this.props.cursor.deref()}
; } }); var data = immstruct({ something: 'initial' }); React.render(
, document.body); // Won't re-render React.render(
, document.body); ``` --- # Part 3: Assignments 1. Use Omniscient's `shouldComponentUpdate` in React (21) --- # Referentially Transparent Components ## Syntactic Suger for Functional UIs And Content First Focus ```js var component = require('omniscient'); var h1 = React.DOM.h1; var Greeting = component(function (props) { return h1({}, 'Hello, ' + props.name) }); React.render(Greeting({ name: 'Peter Quill' }), el); ``` --- # Combining with ES2015 (ES6) and JSX ```js var component = require('omniscient'); var Greeting = component(({name}) =>
Hello, {name}!
); React.render(Greeting({ name: 'Angela' }), el); ``` --- # Always With `shouldComponentUpdate` ```js var component = require('omniscient'); var i = 0; var Greeting = component(function ({name}) { i++; return
Hello, {name}!
; }); React.render(Greeting({ name: 'Starlord' }), el); // Won't do re-render React.render(Greeting({ name: 'Starlord' }), el); console.log(i); //=> i === 1 ``` --- # Composing Multiple Functional Components ```js var component = require('omniscient'); var NameBox = component(function ({name}) { return
{name}
; }); var Greeting = component(function (props) { return
Hello, {NameBox(props)}!
; }); React.render(Greeting({ name: 'Starlord' }), el); ``` ??? Here we also see the interobability with Omniscient and JSX. --- # Omniscient with JSX ```js var omniscient = require('omniscient'); // Activate "always JSX" for Omniscient var component = omniscient.withDefaults({ jsx: true }); var NameBox = component(function ({name}) { return
{name}
; }); var Greeting = component(function (props) { return
Hello,
!
; }); React.render(Greeting({ name: 'Starlord' }), el); ``` --- # Compose with children ```js // Activate "always JSX" for Omniscient var component = omniscient.withDefaults({ jsx: true }); var NameBox = component(function ({children}) { return
{children}
; }); var Greeting = component(function ({name}) { return
Hello,
{name}
!
; }); React.render(Greeting({ name: 'Starlord' }), el); ``` --- # Part 3: Assignments 1. Hello Omniscient! (22) 2. Using Omniscient with JSX (23) 3. Implement List Of Omniscient Items (24) 4. Advanced: Make a simple TODO app With Cursors (25) --- # Mixins for React Life Cycle Methods ```js var mixins = { componentDidMount: function () { var element = React.findDOMNode(this); // do something with element } }; var Greeting = component(mixins, function ({name}) { return
Hello, {name}!
; }); React.render(Greeting({ name: 'Natalia Romanova' }), el); ``` --- # Accessible Mixins Through Render Function ```js var mixins = { onClick: function (event) { console.log('Clicked:', this.props.name); } }; var Greeting = component(mixins, function (props) { return
Hello, {props.name}!
; }); React.render(Greeting({ name: 'Natalia Romanova' }), el); ``` --- # Functional style ```js function onClick (props) { return function onClickFunction (event) { console.log('Clicked:', props.name); }; } var Greeting = component(function (props) { return
Hello, {props.name}!
; }); React.render(Greeting({ name: 'Natalia Romanova' }), el); ``` --- # Part 3: Assignments 1. Add Life Cycle Mixins (26) 2. Advanced: Create search (27) --- # Typical Omniscient Flow ```js var Count = component(({counter}) =>
Count {counter.deref()}!
counter.update(n => n + 1)}>inc
counter.update(n => n - 1)}>dec
); var data = immstruct({ counter: 42 }); data.on('swap', render); render(); function render () { React.render( Count({ counter: data.cursor('counter') }), el); } setInterval( () => data.cursor('counter').update(i => i + 1), 2000); ``` --- class: center, middle # ? --- class: center, middle # [@torgeir](http://twitter.com/torgeir) # [@mikaelbrevik](http://twitter.com/mikaelbrevik)