My favorite state management technique in Angular — RxJS Behavior Subjects

Most of the apps I build in Angular are fairly small, we build many small front end apps instead of a few larger ones. Historically, my team and I had always just relied on the standard input/emitter Angular way of component interaction, which worked well most of the time but could lead to the occasional excessive passing between sibling components. We had looked into NgRx and other flux implementations but they felt a bit overkill for the size of our applications. Recently, we discovered the solution to our state management needs — the RxJS Behavior Subject!

Photo by Alex Iby on Unsplash

Behavior subjects are similar to regular subjects in RxJS, except they hold onto the “current value”, allowing observers to view the value even if it was last updated prior to subscription. Like subjects, they allow “multicasting”, or simultaneously updating all listeners. What this means is you can keep your behavior subject in a place accessible by multiple components, such as a service, then subscribe to it in multiple components and have all of them receive updates as they occur, regardless of the position of those components in the hierarchy — which is super neat!

This blog is going to show a simple counter app I built to show how behavior subjects work, you can view the source code on Github by clicking here.

Example application, clone it from github and take it for a spin!

The example app is a simple counter with buttons to increment, decrement, and reset the count back to 0. There is a reusable component that is listening to the behavior subject — twice! Both instances of the component will update simultaneously anytime there is a change in the current value stored in the behavior subject. Let’s look at how it works.

In the service, this is how the behavior subject is created. I am using an interface called Count to enforce the object structure acceptable for the behavior subject. initalCountis what the initial value of the count should be (this is also used when resetting). Line 11 is where a new behavior subject is instantiated with 0 as its first value.

There are three methods I made for interacting with the behavior subject. First there is getCount(), which enables a component to receive and subscribe (listen) to the behavior subject. Next, setCount() allows a new current value to be provided to the behavior subject, overwriting the older value in the process. It requires the current value and the delta, or change in value, so that the new value can be computed. Finally, resetCount() reuses that initialCount variable that resets the count back to {value: 0} again. Lets see these methods in action.

Above is the component with the buttons that control updating the behavior subject. The increment, decrement, and reset functions are called on click on their corresponding buttons. When the component is initialized in ngOnInit, it subscribes the the behavior subject so it has access to the current value, which is necessary for changing it. Now lets look at the observer components.

Here is the component displaying the current behavior subject value. This component is instantiated twice, to have two unique, simultaneous listeners. They don’t modify the behavior subject like the previous component, but only passively subscribe to receive updates. In this simple example it’s not particularly impactful — but imagine this was a reusable component that was embedded in very different parts of the app hierarchy but always needed this information. This makes it far simpler to provide the component with the data it requires, instead of passing data down from parent components!

If you console.log the behavior subject, you can actually see something really cool — check out the observers property — we see 3! One for the first component that modifies the behavior subject, and two more for the components only listening. The behavior subject itself keeps track of this, which is both useful and fascinating. The current value can also be seen, as well as data pertaining to the state of the observable.

I hope this example has helped someone understand the power and simplicity of working with behavior subjects. If you have questions or ideas as to how these can be used, please leave them in the comments!