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!!
Reactive Programming with RxJS
By Mika Kalathil
Reactive Programming with RxJS
- 831