Cycle.js - Functional reactive UI framework (Nikos Kalogridis)
-
Upload
greecejs -
Category
Technology
-
view
127 -
download
3
Transcript of Cycle.js - Functional reactive UI framework (Nikos Kalogridis)
WHY ANOTHER FRAMEWORK?Programming is hard!Complexity of Web apps is growing exponentiallyAsynchronous programming complicates thingseven more
CYCLE.JS FEATURESFunctionalReactiveUnidirectonal flow of dataVirtual DOMA Cycle.js program is a pure function - no sideeffects
CYCLE.JS HISTORYNov-2014 - Initial commit on github based on RxJsNov-2015 - A fork of the project was made basedmost.jsJun-2016 - Merged back this time supportingxstream, Rxjs v4, Rxjs v5 and most.jsTC39 Observable proposalFeb-2017 - Dropped stream adapters and now usesObservable to convert between streams. Alsodropped support for Rxjs v4
MAP
Returns a new array with the result of applying afunction on each element of the array
var myArray = [1, 2, 3, 4, 5];
myArray.map(function (value) { return value + 1; });
// -> [2, 3, 4, 5, 6]
FILTER
Returns a new array with all elements that pass thetest implemented by the provided function
var myArray = [1, 2, 3, 4, 5];
myArray.filter(function (value) { return value < 4; });
// -> [1, 2, 3]
REDUCE
Reduces the elements to a single value applying afunction to each of them
var myArray = [1, 2, 3, 4, 5];
myArray.reduce(function (acc, value) { return acc + value; }, 0);
// -> 15
IMPERATIVE VS DECLARATIVEGiven an array of numbers return the numbers that
are less than 4 and add to each of those 10var myArray = [1, 2, 3, 4, 5]; var result = []; var i = 0;
for (i; i < myArray.length; i += 1) { if (myArray[i] < 4) { result.push(myArray[i] + 10); } }
var myArray = [1, 2, 3, 4, 5]; var result = myArray .filter((value) => value < 4) .map((value) => value + 10);
HIGHER ORDER FUNCTIONEXAMPLES
function add(amount) { return function (value) { return value + amount; } }
function lessThan(amount) { return function (value) { return value < amount; } }
var result = myArray.filter(lessThan(4)).map(add(10));
SIDE EFFECTSvar a = 0;
function impure(x) { a = x + a; }
function impure(x) { console.log(x); return x + 1; }
CALLBACKSvar counter = 0;
function callback() { counter += 1;}
document .getElementById('myButton') .addEventListener('click', callback);
var xhr = new XMLHttpRequest(); xhr.open('GET', '/server', true);
xhr.onload = function () { // Request finished. Do processing here. };
PROMISESvar requestPromise = fetch({url: 'http://www.google.com'});
requestPromise .then(function (response) { // do something with the response }) .catch(function (error) { // handle the error });
GENERATORS / YIELDfunction* foo () { var index = 0; while (index < 2) { yield index++; } } var bar = foo();
console.log(bar.next()); // { value: 0, done: false } console.log(bar.next()); // { value: 1, done: false } console.log(bar.next()); // { value: undefined, done: true }
ASYNC / AWAITasync function save(Something) { try { await Something.save(); } catch (ex) { //error handling } console.log('success');}
OBSERVABLE// data$ is an Observable object var subscription = data$.subscribe( { next: function (value) { // handle next value }, error: function (error) { // handle error }, complete: function () { // finished so do cleanup... } } );
REACTIVE PROGRAMMINGis programming with data streams (synchronous orasynchronous)on top of that you are given an amazing toolbox offunctions to combine, create, filter any of thosestreams
RXJS EXAMPLEimport Rx from 'rxjs/Rx';
let counter = 0;
const increaseButton = document.querySelector('#increase'); const increaseClick$ = Rx.Observable.fromEvent(increaseButton, 'click');
increaseClick$.subscribe({ next: function () { // click received counter += 1; console.log(counter); } });
RXJS EXAMPLE REVISEDimport Rx from 'rxjs/Rx'; const increaseButton = document.querySelector('#increase'); const increaseClick$ = Rx.Observable.fromEvent(increaseButton, 'click'); const counter$ = increaseClick$ .mapTo(1) // always maps to a constant value .scan((acc, value) => acc + value, 0); // hint: reduce
counter$.subscribe({ next: function (counter) { // new count event received console.log(counter); } });
OTHER TYPES OF STREAMSRx.Observable.from([1, 2, 3, 4, 5]) .filter((x) => x < 4) .map((x) => x + 10) .subscribe({ next: (value) => console.log(value), complete: () => console.log('done') });
// ->// 11// 12// 13// done
PROMISE AS A STREAMconst myPromise = new Promise((resolve) => resolve('hello')); Rx.Observable.from(myPromise) .subscribe({ next: (value) => console.log(value), complete: () => console.log('done') });
// ->// hello // done
COMBINING STREAMSconst data1$ = Rx.Observable.from([1, 2, 3]);const data2$ = Rx.Observable.from([6, 7, 8]);Rx.merge(data1$, data2$) .subscribe({ next: (value) => console.log(value) });// ->// 1 // 6 // 2 // 7 // 3 // 8
function main(sources) { const model$ = sources .DOM.select('.increase').events('click') .mapTo(1).fold((acc, value) => acc + value, 0);
const vtree$ = model$.map((value) => div([ button('.increase', 'Increase'), span(value) ]) );
return {DOM: vtree$}; }
Cycle.run(main, { DOM: makeDOMDriver('#app') });
NO SIDE EFFECTS
SourcesSinks
main()
DOM side effects
HTTP side effects
Other side effects
pure dataflow
PROSTruly reactive programming styleDeclarative UI designFast - thanks to Snabdom and xstreamFractal state management
CONSBrain rewiring for using functional reactive styleRelatively small community compared to React orAngularSteep learning curve especially on stream librariesLacks a complete UI component library (as of today)
USEFUL LINKShttps://cycle.js.org/http://widdersh.in/tricycle/https://github.com/cyclejs-communityhttps://gitter.im/cyclejs/cyclejshttps://github.com/staltz/cycle-onionifyhttps://github.com/cyclejs-community/cyclic-routerhttp://staltz.com