Sharing UI Event State in React With RxJS
Tags: react, javascript, typescript
Published: 2020-02-08 01:40:33

This piece is a breakdown of a nifty solution to sharing UI event data between React components, which has been a recurring challenge for me over time. It’s a strategy I recently used in a React/ TypeScript project, but it’s applicable to any front-end JavaScript framework.
This piece is primarily about reactive programming using ReactiveX streams, via the RxJS JavaScript library.

## The Problem

Generally, click handlers (or any UI event handlers) in React are somehow bound to the state, either inside the component or in a parent/child.
One of the first components we learn to write from the docs is a stateful class, with a handler that increments a value in the state or something. It works — there’s no doubt — but the combination of conforming to a top-to-bottom data flow and remaining in the virtual DOM sphere without querying the document requires trade-offs. Things to keep in mind:

  - **Reconciliation:** Is all the diffing really worth it for UI events? This has a high impact on low-CPU devices. If your app needs a smooth, complex UI, you’re at risk of blocking the UI because of it.
  - **Stateful UI components:** If you need to make a request based on a DOM event in another part of the app (example to follow), maintaining a separation of concerns will be a challenge. Remember we want to keep UI components “dumb” and void of business logic.
  - **Prop** threading: Not the end of the world, but boy do we hate it when there’s a lot of it.

It’s for the above reasons that using frameworks like React aren’t recommended for TV-based applications.

I recently needed to access innerHTML data from a component that was multiple children deep in the component hierarchy. On clicking the item, I needed to use its value to make a request in the outer most parent. Like this:

![Alt text of image](https://miro.medium.com/max/2160/1*M2HmDF8kGkrdYySmCBDRBg.jpeg)

The UI is determined by the shape of a network response that contains a reference to the component types and data contained within it, so it’s important the list content and request itself be as content-agnostic as possible.

## The Solution: Rx, BehaviorSubject

For the last year or so, I’ve been working on web-based applications that run on a living room TV’s and gaming consoles. The high user expectations Netfilx, Hulu, and other services set — together with the difficulty of building for TV browsers — makes it an interesting challenge, and one tool we have learned to be extremely effective for our needs is RxJS.

Rx is an implementation of a programming paradigm called reactive programming that’s used across multiple languages — in JavaScript’s case, RxJS. Regardless of your front-end language preference, an event-driven UI can become complex and reach a point where thinking in streams that respond to events as they happen becomes easier to deal with than state changes as events happen.

The idea here is to store a reference to the value of a selected DOM element and access it in other sections of our application (not limited to the UI, though). We want to subscribe to the values that get emitted by this storage mechanism and update them when the user selects a new one. The implementation is simple and consists of the following steps:

  - Create a new BehaviorSubject with a default value (the store that we’ll 
subscribe to in other components)
  - Create a method to update the subscription
  - Implement the click handler
  - Subscribe to the `BehaviorSubject` to get the latest emitted value

The code looks like this in order:


```javascript
// 1: create the BehaviorSubject
export const featuredCategory$ = new BehaviorSubject("").pipe(
  distinctUntilChanged(),
  skip(1)
);
// 2: create a method to update the BehaviorSubject
const setfeaturedCategory = (category: string): void => featuredCategory$.next(index);
```

We can now use the `BehaviorSubject` to subscribe and update:

```javascript
// 3: Implement the click handler
<li onClick={(category): void => setfeaturedCategory(category)}>{category}</li>
// 4: Subscribe to the behaviorSubject to get the latest emitted value

// <=== Anywhere in our app ===>
import { featuredCategory$ } from "component";
featuredCategory$.subscribe((category: string): void => this.setState({ selectedCategory: category }))
```

As you can see, we now read our state with much more simplicity. Below are some great advantages of using this method.

  - <b>Composition:</b> Because Rx is all about streams, it’s easy to use them in combination with other streams if I need to.

  - <b>Flexibility:</b> RxJS ships with a bunch of methods I can use to manipulate my streams as needed — like if I needed to delay the emission of the emitted value only the first time on page load, for example.

  - <b>Control:</b> If I wanted to stop listening to value changes after a certain condition is met, all I have to do is unsubscribe.

```javascript
featuredCategory$.unsubscribe();
```

Pretty cool, eh? We’re only starting to scratch the surface of this powerful tool. I thought about sharing this nifty trick just in case you find yourself in a similar situation. Hope it’s helpful!