Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Thinking Reactive in JavaScript

Ivan Jovanovic
November 24, 2017

Thinking Reactive in JavaScript

Talk about Reactive programming in JS, RxJS, functional programming and Cycle.js

Ivan Jovanovic

November 24, 2017
Tweet

More Decks by Ivan Jovanovic

Other Decks in Technology

Transcript

  1. • External service calls • Better performance • Highly testable

    • Abstraction over all async processes • Predictable code • Extendable code
  2. Reactive programming in JS • RxJS - the most popular,

    biggest • MostJS - best performance • Bacon.js • XStream - the smallest
  3. +

  4. + +

  5. Features • Functional (just write pure functions) • Reactive •

    Testable • Composable • Explicit dataflow • Made for large codebases
  6. Drivers - side effects • HTTP • DOM • WebSockets

    • Local storage driver • HTML5 Notifications driver • …
  7. Cycle.js official packages • DOM - collection of drivers that

    work with DOM; it has DOM driver and HTML driver, based on snabdom virtual DOM library • History - driver for History API • HTTP - driver for HTTP requests, based on superagent • Isolate - function for making scoped dataflow components • Most-run - `run` function for apps made with `most` • Run - `run` function for apps made with `xstream` • RxJS-run - `run` function for apps made with `rxjs`
  8. import xs from 'xstream'; import { run } from '@cycle/run';

    import { div, button, p, makeDOMDriver } from '@cycle/dom'; function main(sources) { const action$ = xs.merge( sources.DOM.select('.decrement').events('click').map(ev => -1), sources.DOM.select('.increment').events('click').map(ev => +1) ); const count$ = action$.fold((acc, x) => acc + x, 0); const vdom$ = count$.map(count => div([ button('.decrement', 'Decrement'), button('.increment', 'Increment'), p('Counter: ' + count) ]) ); return { DOM: vdom$, }; } run(main, { DOM: makeDOMDriver('#main') });
  9. function main(sources) { const action$ = xs.merge( sources.DOM.select('.decrement').events('click').map(ev => -1),

    sources.DOM.select('.increment').events('click').map(ev => +1) ); const count$ = action$.fold((acc, x) => acc + x, 0); const vdom$ = count$.map(count => div([ button('.decrement', 'Decrement'), button('.increment', 'Increment'), p('Counter: ' + count) ]) ); return { DOM: vdom$, }; }
  10. View + CSS const style = { backgroundColor: 'blue', width:

    '60px', height: '60px' } const vdom$ = count$.map(count => div([ button('.decrement', { style }, ’Decrement’), button('.increment', { style }, ’Increment’), p('Counter: ' + count) ]) );
  11. import { makeHTTPDriver } from ‘@cycle/http'; function main(sources) { const

    request$ = xs.periodic(1000) .mapTo({ url: 'http://localhost:3000', category: 'api', }); const vdom$ = sources.HTTP.select('api') .flatten() .map(res => res.body) .startWith({ response: ‘’ }) .map(result => div([ h2('.label', `Response from the server: ${result.response}`) ]) ); return { DOM: vdom$, HTTP: request$ }; } run(main, { DOM: makeDOMDriver('#main'), HTTP: makeHTTPDriver() });
  12. function main(sources) { const request$ = xs.periodic(1000) .mapTo({ url: 'http://localhost:3000',

    category: 'api', }); const vdom$ = sources.HTTP.select('api') .flatten() .map(res => res.body) .startWith({ response: ‘’ }) .map(result => div([ h2('.label', `Response: ${result.response}`) ]) ); return { DOM: vdom$, HTTP: request$ }; }
  13. const vdom$ = sources.HTTP.select('api') .flatten() .map(res => res.body) .startWith({ response:

    '' }) .map(result => div([ h2('.label', `Response: ${result.response}`) ]) );
  14. import isolate from '@cycle/isolate'; const sources = {DOM: sources.DOM}; const

    childComponent = isolate(Component)(sources); const childComponentVDom$ = childComponent.DOM; const childComponentValue$ = childComponent.value;
  15. Conclusion • Old paradigm with the new usage • Not

    for everyone • Perfect for real time apps that require high performance • Testable, predictable code • One interface for all async processes