Reactive Programming with RxJS

 

We've already seen RxJS

 

 
var makeAjaxCall = function(method, url) {
  return new Observable(function(observer) {
    var request = new XMLHttpRequest()

    request.open(method.toUpperCase(), url, true)

    request.onload = function() {
      if (request.status >= 200 && request.status < 400) {
        var data = JSON.parse(request.responseText)

        observer.next(data)
        observer.complete(request)
      } else {
        observer.error(request)
      }
    }

    request.onerror = function() {
      observer.error(request)
    }

    request.send()

    return () => request.abort()
  })
}

Observable.fromEvent(myElement, 'click')
  .switchMap(() => makeAjaxCall('get', '/my-url'))
  .map(data => data.someProperty)
  .subscribe(data => dom.data = data)
new Observable(function(observer) {
  ...
})

Observable vs Observer

 

An Observer emits updates to the Observable

Updates subscribers

 

So how do we use this?

 
import 'rxjs/add/operator/filter'
import 'rxjs/add/operator/switchMap'
import 'rxjs/add/operator/catch'
import {BehaviorSubject} from 'rxjs/subject/BehaviorSubject'

const CREATE = Symbol('MyClass:create')
const UPDATE = Symbol('MyClass:update')
const AJAX_URL = '/my-url'

class MyClass {
  private _actions: BehaviorSubject = new BehaviorSubject({action: '', payload: ''})
  public currentData = {}

  constructor() {
    let create = this._actions
      .filter(({action}) => action === CREATE)
      .switchMap(({payload}) => this._createData(payload))

    let update = this._actions
      .filter(({action}) => action === UPDATE)
      .switchMap(({payload: [id, data]}) => this._updateData(id, data)

    Observable.merge(update, create)
      .subscribe(data => this.currentData = data)
  }

  public create(data) {
    this._actions.next({action: CREATE, payload: data})
  }

  public update(id, data) {
    this._actions.next({action: UPDATE, payload: [id, data]})
  }

  private _updateData(id, data) {
    return makeAjaxCallObservable('put', `${AJAX_URL}/${id}`, data)
      .catch(...)
  }

  private _createData(data) {
    return makeAjaxCallObservable('post', AJAX_URL, data)
      .catch(...)
  }
}

Lets break it down

 
import {BehaviorSubject} from 'rxjs/subject/BehaviorSubject

class MyClass {
  private _actions: BehaviorSubject = new BehaviorSubject({action: '', payload: ''})
}

Subjects are both and Observer and an Observable

Lets break it down

 
class MyClass {
  private _actions: Rx.BehaviorSubject = new Rx.BehaviorSubject({action: '', payload: ''})
  
  constructor() {
    this._actions
      .filter(({action}) => action === 'HI')
      .map(({payload}) => payload)
      .subscribe(data => console.log('HI was receieved with: ' + data))
  }
  
  emit(action, payload) {
    this._actions.next({action, payload})
  }
}

var c = new MyClass()


c.emit('HI', 'testtinnggg')
const CREATE = Symbol('MyClass:create')
const UPDATE = Symbol('MyClass:update')
const AJAX_URL = '/my-url'

class MyClass {
  private _actions: BehaviorSubject = new BehaviorSubject({action: '', payload: ''})
  public currentData = {}

  constructor() {
    let create = this._actions
      .filter(({action}) => action === CREATE)
      .switchMap(({payload}) => this._createData(payload))

    let update = this._actions
      .filter(({action}) => action === UPDATE)
      .switchMap(({payload: [id, data]}) => this._updateData(id, data)

    Observable.merge(update, create)
      .subscribe(data => this.currentData = data)
  }

  public create(data) {
    this._actions.next({action: CREATE, payload: data})
  }

  public update(id, data) {
    this._actions.next({action: UPDATE, payload: [id, data]})
  }

  private _updateData(id, data) {
    return makeAjaxCallObservable('put', `${AJAX_URL}/${id}`, data)
      .catch(...)
  }

  private _createData(data) {
    return makeAjaxCallObservable('post', AJAX_URL, data)
      .catch(...)
  }
}

Let's Revisit

What about support for node callbacks and promises??????

import fs from 'fs'

var readFile = Observable.bindNodeCallback(fs.readFile),
    create = Observable.fromPromise(MyApi.create)

readFile('myFile/path.json')
  .mergeMap(create)
  .subscribe(createFile => ...)

well, that was easy...

Don't forget about ngrx/store!!

Time to start creating!!

Made with Slides.com