Beyond flux. Going full cycle with FRP

I'm online!

Complex frontend UIs

Interactive UIs after page rendering

IHM à client semi-lourd

SPAs

First render, then everything happens without page loads

Two-way data binding

One-direction rendering loop

Flux

Flux

Flux!

Flux!

You can use React without flux

Do you really need it?

You don't need it

You don't need it

So you need it

Functional

... ish

Manual state management

Actions in views

render() {
  return (
    <button onclick={this.handleClick}>
      Click me
    </button>
  );
}
handleClick(e) {
    doStuff();
    this.setState(yolo);
}
handleClick(e) {
    doStuff();
    this.setState(yolo);
}
render() {
  return (
    <ChildComponent
       handlers={this.props.handlers} />
  );
}
handleClick(e) {
    this.props.handleClick(e);
}

Nice architecture

Frustrating implementation

Redux

Simplification, more opinionated version of flux.
3 base concepts

Single source of truth

Only one store describing the whole application
undo / redo

State is read-only

No in-place mutation
No race conditions
Loggable / inspectable evolutions

Changes are made with pure functions

No mutation, only transformations
More composable

Better

Easier to model and reason about than flux, but still a bit manual

Let's try with more suitable tools

Tools better suited to modeling evolutions

Reactive Programming

Mind the hype

Inversion of Control

Describe transformations, let them be called when needed

Observer pattern

Functional Reactive Programming

not really (don't tell Conal Elliott) observable-based programming?

No actions

No dispatchers

No Component Action Creation Factory

Only Observables

Observables

event streams

Combinators

lots of combination functions available

Redux + observables

Angular v2

Uses observables internally
exposes observables in some parts of the public API (forms)

We can do better

Model all the application with observables

Cycle.js

A UI is a cycle between a user and a computer

import Cycle from '@cycle/core';
import {makeDOMDriver} from '@cycle/dom';

function main(sources) {
  const input$ = f(sources.DOM);
  const vtree$ = g(input$);

  return {DOM: vtree$};
}

Cycle.run(main, {
  DOM: makeDOMDriver('#app')
});

MVI

Intent

function intent(DOM) {
  return {
    changeWeight$:
      DOM
        .select('#weight')
        .events('input')
        .map(ev => ev.target.value),
    changeHeight$:
      DOM
        .select('#height')i
        .events('input')
        .map(ev => ev.target.value)
  };
}

Model

function model(actions) {
   return Observable.combineLatest(
    actions.changeWeight$.startWith(70),
    actions.changeHeight$.startWith(170),
     (weight, height) =>
       ({weight, height,
         bmi:
         calculateBMI(weight, height)})
   );
 }

View

function view(state$) {
  return state$
    .map(({weight, height, bmi}) =>
      div([
        renderWeightSlider(weight),
        renderHeightSlider(height),
        h2('BMI is ' + bmi)
      ])
  );
}
function main({DOM}) {
  return {
    DOM:
     view(model(intent(DOM)))
  };
}

Purity

Pure functions everywhere
Transformations from observables to observables

Drivers

Where effects happen
Effects are described in a pure fashion
Very easy to mock

Declarative effects

  
  
  
  
const requests$ = Rx.Observable
 .interval(5000)
 .map(() => 'http://example.org/')

Easy mocking

  
  
  
  
Cycle.run(main, {
  DOM:  myDomMock,
  HTTP: myHttpMock
});

tl;dl:

TIMTOWTDI

Unidirectional UI architectures

RxJS only
Flux
RxJS + react
Redux
Elm

Play with Cycle.js

Best way to get a feel of it

Everything is moving fast

Lots of ideas
No clear consensus (yet?)

Cycle diversity

Generalize for any stream library

xstream

Simpler than RxJS
Forget about drivers
Hot observables by default

Elm: Farewell to FRP

Read list

The Introduction to Reactive Programming you've been missing

http://rxmarbles.com

http://cycle.js.org

Thanks

http://cltdl.fr/gifs

I'm online!

Images