Using RxJS with React.js: Part 3 — Dispatching events from Component
This is the third part of the series.
(Check out FrintJS on GitHub for more documentation on combining the power of RxJS with React)
Unidirectional cycle
Earlier we saw an example of HoC streaming props to the base component. Let’s now look at ways how we can dispatch events from inside the base component, update some value, and the updated value will then be streamed back to the component completing one unidirectional cycle.
We can take the example of a form input field. User types something, the we dispatch a onChange
event, and the Subject updates itself, and then streams the updated value.
Understanding RxJS Subjects
I won’t go too deep into Subjects in this article. But Ben Lesh has a very nice post explaining Subjects in RxJS, which you can read here.
In short, Subjects can be treated as both an Observable, and an Observer.
import { Subject } from 'rxjs';// create a Subject instance
const subject$ = new Subject();// subscribe to it just like an Observable
subject$.subscribe(x => console.log(x));// emit values like an Observer
subject$.next('foo');
subject$.next('bar');
subject$.next('baz');
In our example, we would be using a BehaviorSubject. To keep things simple, let’s say BehaviorSubject is a kind of Subject, that can already start with an initial value.
import { BehaviorSubject } from 'rxjs';const subject$ = new BehaviorSubject('foo');subject$.subscribe(x => console.log(x)); // prints `foo` right away
The base Component with form input
Let’s say this is our base component:
import React from 'react'const MyComponent = React.createClass({
render() {
const { value, handleChange } = this.props;
return (
<div>
<input
type="text"
value={value}
onChange={e => handleChange(e.target.value)}
/> <p>Current value: {value}</p>
</div>
);
}
});
From the base component, we are accessing the props value
and handleChange
. And they are used for showing the current value, and dispatching the new value from the input field respectively.
The observables
We need two different kinds of streams for this. First one is a stream of the input value, and the latter for handling the change.
import { BehaviorSubject, Observable } from 'rxjs';const formInput$ = new BehaviorSubject('foo'); // with initial value
const handlers$ = Observable.of({
handleChange: value => formInput$.next(value)
});// merge them both
const merged$ = Observable.merge(
formInput$.map(x => ({ inputValue: x })),
handlers$
);// props-compatible object
const props$ = merged$
.scan(function (props, emitted) {
return {
...props,
...emitted
};
});
Observing the base Component
Now that we have the props$
observable ready, we can integrate it with our base complement easily using the observe
function from FrintJS:
import { observe } from 'frint-react';const ObservedRoot = observe(function () {
return props$;
})(MyComponent);
Now you can stream the props, including both the input value and the change handler from your HoC, and also trigger changes in the Subject from your Component’s events.
Live demo
Visit this example in JSBin.