DEV Community

Cover image for How I Got Rid of State Observables in Angular
~AlleAmiDev~
~AlleAmiDev~

Posted on • Updated on

How I Got Rid of State Observables in Angular

When developing a complex SPA in Angular, using a state management library makes things so much easier.

The app store acts as a single source of truth and contains all the data that is fundamental to the correct functioning of the app. Thanks to the store, I can access or edit this data from any smart component (or container).

However, it can be frustrating to deal with all the subscriptions to the store; many times I have to deal with multiple @Select() in a single component, each of which returns an Observable of its correspondent property in the app store.

And for each of these Observables, I need to create a subscription that will be destroyed at the end of the component lifecycle…that’s a lot of code!

But what if we could get rid of all the Observables?

In the simplest cases, we can avoid explicit subscriptions using the async pipe, which will subscribe to the Observable and read the last value emitted for us.

Suppose that we have a @Select() decorator like this:

@Select(ListState.SelectAllItems) listItems: Observable<string[]>;
Enter fullscreen mode Exit fullscreen mode

We can use it immediately with the async pipe in our HTML:

<ul>
 <li *ngFor="let item of listItems | async">
   {{item}}
 </li>
</ul>
Enter fullscreen mode Exit fullscreen mode

On the other hand, many cases require us to subscribe to the Observables in our components so that we can use the values they emit in other methods.

(To learn about how to set up a store and see the above examples in a project, you can read my article How to Create a Simple Store in Angular.)


Introducing @ngxs-labs/select-snapshot

@ngxs-labs/select-snapshot is an experimental feature for NGXS developed by NGXS Labs.

Even though it’s still not part of the official NGXS package, it is likely to become an official feature shortly. The package allows us to replace the @Select() decorator with @SelectSnapshot().

But what’s the difference between them?

While the former returns an Observable we need to subscribe to, the latter subscribes to the store for us and returns the last value emitted! To see it in action, let’s install the package:

npm install @ngxs-labs/select-snapshot
Enter fullscreen mode Exit fullscreen mode

And then, let’s include it in our appModule:

@NgModule({
declarations: [
AppComponent,
ListContainerComponent,
ListItemInputComponent,
ListComponent
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
ReactiveFormsModule,
NgxsModule.forRoot([ListState]),
NgxsReduxDevtoolsPluginModule.forRoot(),
NgxsSelectSnapshotModule.forRoot()
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode

Now we can replace the @Select() decorator:

//@Select(ListState.SelectAllItems) listItems: Observable<string[]>;
@SelectSnapshot(ListState.SelectAllItems) listItems: string[];
Enter fullscreen mode Exit fullscreen mode

And use the value emitted from the store without subscribing!

<ul>
 <li *ngFor="let item of listItems">
   {{item}}
 </li>
</ul>
Enter fullscreen mode Exit fullscreen mode

Enjoy!

(This article has been originally published on Medium.)

Discussion (0)