Skip to content

Instantly share code, notes, and snippets.

@art-solopov
Last active November 17, 2018 12:08
Show Gist options
  • Save art-solopov/174935b1164b17ea79b9bb32930035ae to your computer and use it in GitHub Desktop.
Save art-solopov/174935b1164b17ea79b9bb32930035ae to your computer and use it in GitHub Desktop.
A small component using rxjs
import * as rxjs from 'rxjs'
import { map, scan, startWith, shareReplay, take, filter } from 'rxjs/operators'
import Mustache from 'mustache'
const TEMPLATE = require('raw-loader!./templates/counter.mustache')
Mustache.parse(TEMPLATE)
export default class Counter {
constructor () {
const initialState = { counter: 0 }
this.stateSubject = new rxjs.Subject()
this.state$ = this.stateSubject.asObservable()
.pipe(
scan((acc, newVal) => Object.assign({}, acc, newVal)),
startWith(initialState),
shareReplay(1)
)
}
swap(fn) {
this.state$.pipe(take(1))
.subscribe(state => this.stateSubject.next(fn(state)))
}
mount (el) {
this.state$.subscribe(state => this.render(el, state))
const evOb = rxjs.fromEvent(el, 'click')
const addOb = evOb.pipe(filter(e => e.target.name == 'add'), map(_e => +1))
const subOb = evOb.pipe(filter(e => e.target.name == 'sub'), map(_e => -1))
const alterCounter = (x) => ({counter}) => ({counter: counter + x})
rxjs.merge(addOb, subOb).subscribe(x => this.swap(alterCounter(x)))
}
render(el, state) {
el.innerHTML = Mustache.render(TEMPLATE, state)
}
}
<div>{{ counter }}</div>
<div>
<button name="add">+</button>
<button name="sub">&ndash;</button>
</div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment