Deep dive into observed Components with React.js and FrintJS

综合技术 Medium

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
...
;
}
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!

Medium稿源:Medium (源链) | 关于 | 阅读提示

本站遵循[CC BY-NC-SA 4.0]。如您有版权、意见投诉等问题,请通过eMail联系我们处理。
酷辣虫 » 综合技术 » Deep dive into observed Components with React.js and FrintJS

喜欢 (0)or分享给?

专业 x 专注 x 聚合 x 分享 CC BY-NC-SA 4.0

使用声明 | 英豪名录