Using RxJS with React.js: Part 3 — Dispatching events from Component

This is the third part of the series.

Illustration of unidirectional flow between Subject and Component

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.