Deep dive into observed Components with React.js and FrintJS

Fahad Heylaal
FrintJS
Published in
4 min readDec 7, 2017

Our focus in this article will be about using the observe higher-order component, shipped from frint-react package.

Even though FrintJS is rendering library agnostic (and supports React and Vue.js both), we will stick to React.js only for the sake of this article.

To make the most out of this, it is advised that you read these previous articles from our blog first:

Higher-order component

The API of the observe higher-order component (HoC) is quite simple:

import React from 'react';
import { observe } from 'frint-react';
function MyComponent(props) {
return <div>...</div>;
}
const ObservedComponent = observe(fn)(MyComponent);export default ObservedComponent;

It receives a function (that we called fn above), where you can generate your props that will be ultimately passed to your target component, and returns a function that accepts the component you want to observe (in this case MyComponent).

Generating props synchronously

The fn function also gives you access to the FrintJS App’s instance:

const ObservedComponent = observe(function (app) {
// this will be the `props` in MyComponent
return {};
})(MyComponent);

Since you have access to your app instance, you can also get values from it, including providers:

const ObservedComponent = observe(function (app) {
return {
appName: app.getName(),
foo: app.get('foo'),
};
})(MyComponent);

Now your MyComponent will receive both appName and foo as props.

Props as an Observable

The observe HoC is powerful enough to return props as a stream expressed with an RxJS Observable too.

Think of an interval, that changes over time:

import { interval } from 'rxjs/observable/interval';const interval$ = interval(1000); // emits every 1 second

We can map it further, to convert it to a props-compatible object that our MyComponent can understand:

import { interval } from 'rxjs/observable/interval';
import { map } from 'rxjs/operators/map';
const interval$ = interval(1000);const props$ = interval$.pipe(
map(x => ({ interval: x }))
);

We just created a new props$ observable, that is mapping interval$ into emitting an object with this structure: { interval: 1 }.

Now we can connect it to our MyComponent using the observe HoC:

import { interval } from 'rxjs/observable/interval';
import { map } from 'rxjs/operators/map';
const ObservedComponent = observe(function (app) {
const interval$ = interval(1000);
return interval$.pipe(
map(x => ({ interval: x }))
);

})(MyComponent);

When this component is rendered, MyComponent will be receiving the prop interval that will keep incrementing every second triggering a re-render.

Accessing parent component’s props

Before returning the props Observable, it is possible that you may need to access the props passed from a parent component (if any).

In React, props passed down from parent components can change any time. Because they have this dynamic nature, the observe HoC gives you access to parent props as an Observable:

const ObservedComponent = observe(function (app, props$) {
// ...
})(MyComponent);

In addition to your FrintJS App instance (app), there is a second argument props$, which is props passed down to you from the parent Component expressed as an Observable.

Using helper function for generating props stream

The examples above were pretty straight forward, and worked with only a single Observable. But as your application grows, there will be times, when you need to work with multiple Observables and return a single props stream.

This is where a helper function called streamProps shipped with frint-react can come handy.

If you are an RxJS ninja, you may skip this part =D

The streamProps function will allow you to keep setting values (with chaining) until you are done and then generate a single Observable out of all the set values.

Code example:

import { observe, streamProps } from 'frint-react';const ObservedComponent = observe(function (app, props$) {
return streamProps()
// synchronous values
.set('foo', 'foo value')
.set({ bar: 'bar value' })
// values from Observables
.set(
interval$, // rest of the arguments are mappers
x => ({ interval: x })
)
.set(
props$,
parentProps => parentProps.somePropName,
somePropName => ({ baz: somePropName })
)
// generate a single Observable of props
.get$();
})(MyComponent);

The code above is generating a props stream consisting of four props together:

  • foo: with value foo value
  • bar: with value bar value
  • interval: with an integer value that keeps incrementing
  • baz: which has a value coming from a prop (somePropName) passed from parent component

All these four props are then made available to MyComponent.

Starting with default props

Depending on the asynchronous nature of Observables, some may or may not fire right away. In that case, you may want to pass some default props to your target component before new values are generated.

The streamProps helper function receives an optional first argument, where you can pass your default props:

import { streamProps } from 'frint-react';const defaultProps = {
foo: 'n/a',
bar: 'n/a',
baz: 'n/a',
};
const props$ = streamProps(defaultProps)
.set(...)
.get$();

It will then start the props stream with n/a as initial values, and as soon as values for these props are available, they will be updated and streamed to your target component.

Summary

To summarize, we can say that the observe HoC does the following:

  • Wraps your target component, returning a new observed component
  • Gives access to FrintJS App instance
  • Gives access to props passed from parent component as an Observable
  • Allows you to generate props for your target component either synchronously or expressed with an Observable

This approach helps and encourages you write your React components in a stateless way as much as possible, leaving it free of any logic and deal with props only.

Find us on Twitter if you have any feedback for us!

--

--

Fahad Heylaal
FrintJS

Maker of things · JavaScript · RxJS · ReactJS