Shared State | Progressive Reactivity in Angular
Tags: angular, rxjs, reactive, stateadapt
Published: 2022-07-05 09:23:12

---
title: Shared State | Progressive Reactivity in Angular
published: true
description: Guaranteed consistency doesn't have to be hard.
tags: angular, rxjs, reactive, stateadapt
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/obwfiorml7qte8jno2ta.png
# cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sk1qt24qotowmv86c0lz.png
# Use a ratio of 100:42 for best results.
series: Progressive Reactivity in Angular
---

The more stateful your application is, the more likely you will run into inconsistent state, or state that doesn't react. For example: A user opens a message but the unseen message count doesn't react.

There are many ways to code reactively in Angular, from 2-way binding (yes) to advanced RxJS. Some teams decide on a single application-wide strategy, which means the strategy for every feature will be as complex as the most advanced feature. This reduces productivity and happiness.

Other teams prefer not to have any single strategy, but to allow each developer to come up with the easiest way to develop each feature independently, adapting the complexity of the solution to the complexity of the problem. This is fast at first, but complexity is rarely static—it is impossible to anticipate every user need and every requirement change. This matters because at every stage there are multiple ways of handling higher complexity, and some of them are dead ends: They can handle the next level of complexity reactively, but they have limitations that cap them at that level. They are also significantly different from the solutions that _can_ handle further levels of complexity, so you have to go backwards before you can go forwards again.  

So, we don't want premature complexity, but we also don't want to get stuck with an awkward mess that is hard to adapt to higher complexity. The ideal strategy would be simple at the very beginning, but also easy to adapt to higher and higher complexity at any stage.

How do we know what syntax to avoid then? First we need a solid understanding of the difference between reactive and imperative code.

---

![divider](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/46rby7k8kpgqa11khbbf.png)

### Progressive Reactivity Rule #1:

**Keep code declarative by introducing reactivity instead of imperative code.**

Minimal syntax can grow in many possible ways, both reactively and imperatively, so we need to recognize the difference between reactive and imperative code.

Reactive code is completely self-defined. Nothing else tells it how to change. It manages its own behavior by declaring clear data dependencies.

This is reactive:
```typescript
a$ = new BehaviorSubject(0);
b$ = this.a$.pipe(delay(1000)); // Clear dependency on a$
```

This is imperative:
```typescript
a = 0;
b: number | undefined; // No dependency here

constructor() {
  setTimeout(() => this.b = 0, 1000);
}

changeA(newA: number) {
  this.a = newA;
  setTimeout(() => this.b = newA, 1000);
}
```

Part of what defines `b` has been broken away from `b`'s declaration. You do not know how `b` will behave by looking at `b`'s declaration _or_ at any single `setTimeout`. It's scattered. This is why reactive code is so much easier to comprehend.

But imagine if `b` never changed. It just stayed as `undefined`. Then its initial declaration would describe its behavior completely. So it is already completely declarative, just as it is. No RxJS needed.

All reactive code is declarative, but not all declarative code is reactive. Declarative code is the complete absence of imperative commands controlling state from scattered, out-of-context places. Since we are trying to avoid inconsistent state, which easily happens with imperative code, declarative code is really what we are after. It is only as features become more interactive that code must become both declarative _and_ reactive. 

As long as you do not write imperative code, your code is declarative, no matter what syntax you use. This means you can start with minimal syntax, and only later, when you need it to change over time, modify its declaration instead of having code elsewhere tell it how to be. 

So, always write declaratively, and write reactively when it is required to keep code declarative.

It also doesn't hurt to err on the side of more reactivity if you anticipate higher complexity in the future.

![divider](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/46rby7k8kpgqa11khbbf.png)

---

Alright. We are ready to look at the first levels of complexity. 

## Level 0: Static Content

`const b = 2` is not reactive. Neither is this:

```html
<h1>Hello World!</h1>
```

And that's okay. There is no risk of imperative changes causing inconsistent bugs. All static content is declarative. 

## Level 1: Shared State

Imagine a simple color-picker like this:

![Color Picker 1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b8p8a4nza5opozr1kjzr.png)

### Imperative Trap

Before frameworks like AngularJS, a common way to implement this would have been something like this:
```html
<div id="color-preview" class="aqua">aqua</div>
<button
  id="aqua"
  class="active" 
  onClick="changeColor('aqua')"
>aqua</button>
<button
  id="orange"
  onClick="changeColor('orange')"
>orange</button>
<button
  id="purple"
  onClick="changeColor('purple')"
>purple</button>

<script>
var currentColor = "aqua";
function changeColor(newColor) {
  document.getElementById('color-preview').className = newColor;
  document.getElementById(currentColor).className = '';
  document.getElementById(newColor).className = 'active';
}
</script>
```

And then someone would notice that the color name never changes:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9xar4bi370xhm8kpc09k.png)

So you would change the 1st line of `changeColor` to these 2 lines:

```javascript
  var previewEl = document.getElementById('color-preview');
  previewEl.className =  previewEl.innerText = newColor;
```

Why did we miss this? While we were writing `changeColor`, not every bit of the template was necessarily on our minds. 

Edit: While writing this example, I intentionally forgot to update `#color-preview`'s text. But I unintentionally also forgot to update `currentColor = newColor`. I only noticed this now while implementing this in [StackBlitz](https://stackblitz.com/edit/angular-ivy-cwnz5p?file=src%2Findex.html).

So, basically, imperative code and forgotten DOM updates used to be the norm. The DOM was not reactive. 

### Reactive Solution to Level 1: Shared State

Then Angular and others came along, and now we can implement features like this declaratively. Each part of the template can once again declare what it is, permanently, even though it is no longer static content. The difference is that instead of declaring static content, each piece declares a static _relationship_ to a value that changes.

`#color-preview`'s class was written as `aqua` before. Why? Because that is what the color started as. So we write `[class]="currentColor"`, because _that's what it really is_, across time. Same with the inner text. So we write `{{currentColor}}` for that. 

`button#aqua` started with the class `active`. Why? Because we know that the button should look active when the current color is `aqua`. So we write `[class.active]="currentColor === 'aqua'"`. What does the button do? Well it changes  the current color to `'aqua'`. So that would be `(click)="currentColor = 'aqua'"`

It's easy when we go piece by piece to know why everything started out as what it was, and realize that its current state is always related to a higher, shared state called `currentColor`. We can write entire templates and be confident we didn't miss anything:
```html
<div
  id="color-preview"
  [class]="currentColor"
>{{currentColor}}</div>
<button 
  [class.active]="currentColor === 'aqua'"
  (click)="currentColor = 'aqua'"
>aqua</button>
<button 
  [class.active]="currentColor === 'orange'"
  (click)="currentColor = 'orange'"
>orange</button>
<button 
  [class.active]="currentColor === 'purple'"
  (click)="currentColor = 'purple'"
>purple</button>
```
```typescript
  // Component class
  currentColor = 'aqua';
```

A critical thinker might notice a contradiction now. I'm excited about our declarative templates, but `currentColor = 'aqua'` is not declarative. `currentColor`'s changes are dictated by imperative commands scattered across the template. But this is the best we can do, for a couple of technical reasons:
1. We can only define the template once, but it should be at both the top and the bottom of the causal chain: `currentColor` depends on the button clicks, but the buttons depend in turn on `currentColor`. It's not possible to declare these relationships without circular references. 
2. If we wanted `currentColor` to react to the button clicks, it could not be shared between components because other components don't have access to this button.

**The best we can do is this: Every user event in the template pushes the most minimal change to a single place in our TypeScript, and _then_ everything else reacts to that.**

### Syntactic Dead Ends

2-way data binding is often discouraged, but it's actually fine at this level of complexity. It's as declarative as anything else, as long as there isn't derived state that needs to update. It's not a syntactic dead end either, because it's easy to change

```html
<input [(ngModel)]="currentColor" />
```
to 
```html
<input
  [ngModel]="currentColor$ | async"
  (ngModelChange)="currentColor$.next($event)"
/>
```

But something to watch out for is template logic. For example, if we had `currentCount` instead of `currentColor`, we might end up doing simple math inside our templates, like this:
```html
current count is {{currentCount}}.
Next count: {{currentCount + 1}}.
```
 
This is fine, because it's easy to move elsewhere, but at a certain level of complexity either the processing can't be done in Angular's templating language, or we want to be more expressive with something like `{{nextCount}}`. In that case, we want to officially treat it as derived state. That will be the topic of the next article in this series.