Introduction to Reactive Programming

Tyson Thomas

tysonthomas.90@gmail.com

Events

[{x: 10, y:15}, {x:12, y:18}, {x: 14, y:20}]
....{x: 10, y:15}...{x:12, y:18}...{x: 14, y:20}....

VS

Array

Events and Arrays are both collections

is a Sequence of data over time

Event Stream

Synchronous Array Data is easy to work with

We have all kinds of neat tools for working with synchronous data

  • map
  • reduce
  • filter
  • and so on..

But what about async data?

"Reactive programming is programming with asynchronous data streams."

- Andre Staltz

So what's a stream?

A stream is simply a collection that arrives over time.

Collection

[ 1, 2, 3]

Stream

1

2

3

Observables

Observables are like collections...

Except they arrive over time asynchronously

Observables are like Promises...

Except they work with multiple values.

They clean up after themselves

They can be cancelled

Oh, and they let you map, filter, reduce (and more!)

Observable Example

import {Observable} from './rx'

//Observable constructor
let myObservable = new Observable(observer => {
  observer.next(1);
  observer.next(2);
  observer.next(3);

  observer.complete();
});

myObservable.subscribe(
  val => console.log(val),
  err => console.log(err),
  _ => console.log('done')
);
function* values(){
  yield 1;
  yield 2;
  yield 3;
}
let i = values();

i.next() //{value: 1, done: false}
i.next() //{value: 2, done: false}
i.next() //{value: 3, done: false}
i.next() //{done: true}
let myObservable = new Observable(observer => {
  observer.next(1);
  observer.next(2);
  observer.next(3);

  observer.complete();
});

myObservable.subscribe(
  val => console.log(val),
  err => console.log(err),
  _ => console.log('done')
);
  

Pull

Push

Iterator Pattern

Duality

Observer Pattern

So in Observer Pattern..

 

..Producer Iterates you

Observables can model...

  • DOM Events

  • Timer Intervals

  • Data Requests

  • Animations

Event Observable

import {Observable} from './rx'

const myButton = document.getElementById('myButton');

let clicks$ = new Observable(observer => {

  let onClick = ev => observer.next(ev);

  myButton.addEventListener('click', onClick);

  return () => {
    myButton.removeEventListener('click', onClick);
  }
});


let clickListener = clicks$.subscribe(ev => console.log(ev));

Inputs - .map

const myInput = document.getElementById('myInput');

//stream of keyup Events
let keyups$ = Observable.fromEvent(myInput, 'keyup');

//map to the values
let inputs$ = keyups$.map(ev => ev.target.value);

inputs$.subscribe(text => console.log(text));
//h
//he
//hel
//hell
//hello

Counter - .reduce/.scan

const incrementButton = document.getElementById('increment');
const decrementButton = document.getElementById('decrement');
const counterOutput = document.getElementById('output');

const getValue = ev => parseInt(ev.target.value,10);

let increments$ = Observable.fromEvent(incrementButton, 'click');
let decrements$ = Observable.fromEvent(decrementButton, 'click');

//merge into a single stream, map to int values
let changes$ = Observable.merge(increments$, decrements$).map(getValue);

//scan (reduce) to track the state
let total$ = changes$.scan((total, value) => total + value, 0);

//set count
total$.subscribe(count => {
  counterOutput.innerText = count;
  console.log(count);
});

Search - .flatMapLatest

const myInput = document.getElementById('myInput');

// Get all distinct key up events from the input and only fire if long enough and distinct
var keyup = Rx.Observable.fromEvent(myInput, 'keyup')
              .map(function (ev) {
                return ev.target.value;          //get the input value
              })
              .filter(function (text) {
                return text.length > 2;          // Only if the text is longer than 2 characters
              })
              .debounce(750)                     //Pause for 750ms
              .distinctUntilChanged();           // Only if the value has changed

var searcher = keyup.flatMapLatest(searchWikipedia);

// Search Wikipedia for a given term
function searchWikipedia (term) {
  return $.ajax({
      url: 'http://en.wikipedia.org/w/api.php',
      dataType: 'jsonp',
      data: {
        action: 'opensearch',
        format: 'json',
        search: term
      }
    }).promise();
  }

Search - .flatMapLatest

RX in ReactJS

Data Flow

  • REDUX Store
  • Async Streams - Action 

 

Implementation

      jas-chen/rx-redux

      acdlite/redux-rx

Remember

Resources

Questions?