Here at Reonomy, we have been in the midst of a transition between engineering languages. Our platform was initially built with a mix of AngularJS – and over the past few months, we have made a full transition to the more developer-friendly React.

In order to make this transition feasible, Dmitry Doronin, a software engineer here at Reonomy, created a reactive-hooks library to make some of our more complex calls even more simplified. Below, Dmitry gives the full rundown of the open-sourced reactive-hooks library.

Why Reactive-Hooks?

Web Applications development is all about handling asynchronous calls with multiple events. That’s exactly what RxJS was invented to solve. On the other hand, React is a great library for rendering HTML.

But I couldn’t find any good tool that leverages the power of RxJS and brings it in the React World.

That’s why I created reactive-hooks, and I’m proud to announce that it’s been open-sourced: https://github.com/reonomy/reactive-hooks

If you are on React 16 then probably you are already using hooks and know how much they simplify code. The reactive-hooks library makes RxJS much easier to use by handling Subjects and Observables with familiar React Hooks syntax.

This library is a cornerstone of our front-end (FE). It helped to build a performant and scalable Web Application.

Back six months ago when I just joined Reonomy, the web platform was created as a large single-page application written with AngularJS, jQuery and Lodash sometimes mixed with Python Flask templates.

This solution worked for more than four years when all engineering efforts were focused on data pipelines, machine learning, and scalability. Today, considering our speed of growth and output, we want to deliver more features with less effort.

Our angular-based web stack degraded and required significant engineering efforts even for minor changes.

In the 1st quarter of 2019 we’ve made a decision to move our FE to React, RxJS and Typescript. Now, after three months of intensive work, when we’ve made our first release of this new FE, I’m happy to share my observations and thoughts.

Why React, RxJS and Typescript?

Originally we considered three candidates: React, Angular 7 and VueJS, — but decided to go with React, because it has decent performance, an active community, and the most developed ecosystem.

The ecosystem means that numerous boilerplate (https://material-ui.com/) and advanced components (https://github.com/bvaughn/react-virtualized) come for free.

Typescript makes Javascript code more predictable, it helps to identify obvious bugs in compile-time versus run-time, introduces better development experience because of the language server supported by popular IDEs such as VSCode, Sublime and IntelliJ Idea.

We are using RxJS to manage the application state and reactive-hooks to render this state.
https://www.npmjs.com/package/@reonomy/reactive-hooks

But why should FE engineers care about a state? Here are my thoughts.

Application State and RxJS

Any application has a state. That could be a database or a configuration file or anything else that persists data. This state should be a single source of truth. The role of FE is to get a piece of this state and render it in a human-readable form. Mathematically that means the following:

UI =F(S),
where UI is an HTML markup, F is a filter/map/reduce function and S is a state.

But state S is changing over time t (fig. 1), the HTML page becomes dynamic.

UI(t)=F(S(t — t0)),
where t0 is a moment of time UI was initially rendered.

In other words, FE needs to observe any single moment of time when the state is updated and render a new HTML markup as a reaction to this change. That’s exactly what RxJS is designed to do with its Observables. But how to map RxJS primitives to HTML markup? That can be done with reactive-hooks.

Reactive Hooks Overview

https://www.npmjs.com/package/@reonomy/reactive-hooks

Reactive Hooks is a library for rendering RxJS Observables using React Hooks.

It can be installed along with rxjs using yarn on npm command:

yarn add @reonomy/reactive-hooks rxjs

or

npm install @reonomy/reactive-hooks rxjs --save

This library introduces two fundamental hooks: useRxState and useRxEffect. There are very similar to standard useState and useEffect.

How to use it

Let’s start with an example from React documentation:

import React, { useState } from "react";

function Example() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

As one can see this component will render a paragraph “You clicked 0 times”. Each click on a button will increment this count and update the message accordingly. This component is stateful and non-reusable. To fix it we would need to move count outside of the render function.

import React, { useState } from "react";
import { useRxState } from "@reonomy/reactive-hooks"; 
import { BehaviorSubject } from "rxjs";

const count$ = new BehaviorSubject(0); 

function Example() {
  const [count, setCount] = useRxState(count$);
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

Almost no changes!

1. We imported useRxState hook from the NPM library:

import { useRxState } from '@reonomy/reactive-hooks';

2. Instantiated a new BehaviorSubject with initial value 0:

import { BehaviorSubject } from "rxjs";
const count$ = new BehaviorSubject(0);

3. Replaced useState with useRxState:

const [count, setCount] = useRxState(count$);

Now we have a stateless component. Unfortunately it’s still hard to reuse, because count$ is living in the same file. It should be injected. We can use props or React Context. I’ll show how to use Context, it’s less verbose and more flexible.

Let’s create a new file counter.js with the following content:

import React from "react";
import { BehaviorSubject } from "rxjs";

const count$ = new BehaviorSubject(0);

export const CounterContext = React.createContext(count$);

Now we can import count$ using React Context Hooks:

import React, { useContext } from "react";
import { useRxState } from "@reonomy/reactive-hooks";
import { CounterContext } from "./counter.js";
function Example() {
  const count$ = useContext(CounterContext);
  const [count, setCount] = useRxState(count$);
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

If we need two independent <Example/> components to be rendered on the same page, but with different isolated counters, Context Provider can be used:

import React, { useContext } from 'react';
import { useRxState } from '@reonomy/reactive-hooks';
import { CounterContext, createCounter } from "./counter";

<div>
  <CounterContext.Provider value={createCounter(0)}
    <Example/>
  <CounterContext.Provider>
  
  <CounterContext.Provider value={createCounter(1)}
    <Example/>
  <CounterContext.Provider>
</div>

File counter.js was modified to provide this createCounter() method.

import React from "react";
import { BehaviorSubject } from "rxjs";

export const createCounter = (initialValue) => 
                          new BehaviorSubject(initialValue);

export const CounterContext = 
                      React.createContext(createCounter(0));

I like to think about React Context as a dependency injection for components.


With a help of useRxEffect this component can react on counter changes and print something in console, for example.

import React, { useContext } from "react";
import { 
  useRxState, 
  useRxEffect 
} from "@reonomy/reactive-hooks";
import { CounterContext } from "./counter.js";

function Example() {
  const count$ = useContext(CounterContext)
  const [count, setCount] = useRxState(count$);
  useRxEffect(count$, count => {
    console.log("count is ", count);
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

Each time a counter number is changed, it will be printed in the console.


Think about useRxEffect as a watch function.


There are many other hooks and http helpers. Full API documentation can be found here: https://github.com/reonomy/reactive-hooks

Reactive Hooks Improving Development

We’ve found this marriage of React and RxJS via reactive-hooks to be an elegant solution for our dynamic data-heavy UI here at Reonomy.

We chose React for its ecosystem, and we feel that this state management solution is something valuable that we can contribute back to that ecosystem.

Looking for more about Reactive-hooks and Dmitry’s tips for utilization? Check out even more articles. 

We are elegantly solving problems which have never been solved before.  If this sounds like fun you should come work with us!

Unlock commercial real estate insights and opportunities with ease Start Searching

Related Posts