Cycle.js: Functional and Reactive

21
CYCLE.JS: FUNCTIONAL AND REACTIVE EUGENE ZHARKOV

Transcript of Cycle.js: Functional and Reactive

CYCLE.JS: FUNCTIONAL AND REACTIVE

EUGENE ZHARKOV

Cycle.js

virtual-domRxJS

cycle/corecycle/dom

EXISTED APPLICATION DATA FLOW | FLUX / REDUX

VIEW

DISPATCHERSTORE

actio

nac

tion

actio

n

STORE

USER ACTION

EXISTED APPLICATION DATA FLOW | MODEL VIEW INTENT

VIEW

INTENT

MODEL

USER ACTION

observable

observable

observable

1A

B

2 3

C

I’m loving it

RX UNDER THE HOOD

CODE EXAMPLEfunction intent(DOM, name = '') { const removeClicks$ = DOM.select('.remove-btn').events('click'); const stop$ = removeClicks$; const remove$ = removeClicks$.delay(500); return {stop$, remove$}; }

function model(actions, givenColor$) { const x$ = Observable.interval(50).startWith(0).takeUntil(actions.stop$); const y$ = Observable.interval(100).startWith(0).takeUntil(actions.stop$); const color$ = Observable.merge( givenColor$.takeUntil(actions.stop$), actions.stop$.map(() => '#FF0000') ); return combineLatestObj({x$, y$, color$}); }

function view(state$) { return state$.map(({color, x, y}) => { const style = {color, backgroundColor: '#ECECEC'}; return div('.ticker', {style}, [ h4(`x${x} ${color}`), h1(`Y${y} ${color}`), button('.remove-btn', 'Remove') ]); }); }

BUTTON CLICK

HTML GENERATION

COLOR CHANGE

JSBIN.COM/VUGARUR/

BASIC EXAMPLEimport Cycle from '@cycle/core'; import {div, label, input, hr, h1, makeDOMDriver} from '@cycle/dom';

function main(sources) { return { DOM: sources.DOM.select('.myinput').events('input') .map(ev => ev.target.value) .startWith('') .map(name => div([ label('Name:'), input('.myinput', {attributes: {type: 'text'}}), hr(), h1(`Hello ${name}`) ]) ) }; }

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

JSBIN.COM/VUGARUR/

BASIC EXAMPLEimport Cycle from '@cycle/core'; import {div, label, input, hr, h1, makeDOMDriver} from '@cycle/dom';

function main(sources) { return { DOM: sources.DOM.select('.myinput').events('input') .map(ev => ev.target.value) .startWith('') .map(name => div([ label('Name:'), input('.myinput', {attributes: {type: 'text'}}), hr(), h1(`Hello ${name}`) ]) ) }; }

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

HANDLE EVENTGET INPUT VALUE

DEFAULT VALUE

HTML

JSBIN.COM/VUGARUR/

BASIC EXAMPLEimport Cycle from '@cycle/core'; import {div, label, input, hr, h1, makeDOMDriver} from '@cycle/dom';

function main(sources) { return { DOM: sources.DOM.select('.myinput').events('input') .map(ev => ev.target.value) .startWith('') .map(name => div([ label('Name:'), input('.myinput', {attributes: {type: 'text'}}), hr(), h1(`Hello ${name}`) ]) ) }; }

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

DOM..DRIVER..???

TEXT

DRIVER

▸ DRIVER - effect, “action”

▸ HTTP, WebSocket, User Event, Browser Event etc

▸ SINK - Observable input

JSBIN.COM/LELUHO

SINKfunction main () { return Rx.Observable.timer(0, 1000) .map(i => `Seconds elapsed ${i}`); }

function htmlEffect(text$) { text$.subscribe(text => { const container = document.querySelector('#main'); container.textContent = text; }) }

function consoleEffect(msg$) { msg$.subscribe(msg => console.log(msg)); }

const sink = main(); htmlEffect(sink); consoleEffect(sink);

STREAM GOT INPUT

STEP BY STEP EFFECT

TEXT

SINK

TEXT

RX PLAYGROUD

HTTP://RXMARBLES.COM

JSBIN.COM/VUGARUR/

BASIC EXAMPLE .map(name => div([ label('Name:'), input('.myinput', {attributes: {type: 'text'}}), hr(), h1(`Hello ${name}`) ]) ) }; }

Cycle.run(main, { DOM: ……….. });

CYCLE RUN

GITHUB.COM/CYCLEJS/CORE/BLOB/MASTER/SRC/CYCLE.JS

CYCLE.RUNfunction run(main, drivers) { if (typeof main !== `function`) { throw new Error(`First argument given to Cycle.run() must be the 'main' ` + `function.`) } if (typeof drivers !== `object` || drivers === null) { throw new Error(`Second argument given to Cycle.run() must be an object ` + `with driver functions as properties.`) } if (Object.keys(drivers).length === 0) { throw new Error(`Second argument given to Cycle.run() must be an object ` + `with at least one driver function declared as a property.`) }

let sinkProxies = makeSinkProxies(drivers) let sources = callDrivers(drivers, sinkProxies) let sinks = main(sources) let subscription = replicateMany(sinks, sinkProxies).subscribe() let sinksWithDispose = attachDisposeToSinks(sinks, subscription) let sourcesWithDispose = attachDisposeToSources(sources) return {sources: sourcesWithDispose, sinks: sinksWithDispose} }

BASIC DEMO

HTTP DEMO

JSX MIX DEMO

THANK YOU

@2J2E [email protected]

!

TEXT

RESOURCES

▸ https://jsbin.com/zizabe/

▸ https://jsbin.com/xataxe/

▸ https://jsbin.com/vugarur

▸ https://jsbin.com/dogumi

▸ egghead.io