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[]>;

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

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

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 with the command:

npm install @ngxs-labs/select-snapshot

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 {}

Now we can replace the @Select() decorator:

@Select(ListState.SelectAllItems) listItems:Observable<string[]>;
@SelectSnapshot(ListState.SelectAllItems) listItems: string[];

And use the value emitted from the store without subscribing!

<ul> 
 <li *ngFor="let item of listItems">{{item}}</li>
</ul>

The @ViewSelectSnapshot decorator#

The  select-snapshot library  also exposes a second selector, @ViewSelectSnapshot(). Choosing between this and the simple @SelectSnapshot() can make a difference according to the change detection strategy of the component in which we are using the above decorators.

Let's suppose we have a presentational component with change detection set on OnPush :

@Component({
  selector: 'my-component',
  templateUrl: './my-component.component.html',
  styleUrls: ['./my-component.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})

export class MyComponent {
  @SelectSnapshot(ListState.SelectAllItems) listItems: string[];
  @ViewSelectSnapshot(ListState.SelectFilteredItems) filteredItems: string[];
}

This means that the component will not be constantly checked for changes, but a check will be triggered by any user interaction.

In this situation,  @ViewSelectSnapshot , unlike his sibling @SelectSnapshot, will call the markForCheck() method on the component when the state gets updated, thus triggering the change detection.

For this reason, the NgXs team recommends to use @ViewSelectSnapshot instead of @SelectSnapshot for template binding and dynamic rendering.

In Conclusion#

The select-snapshot library offers very powerful tools to avoid subscribing to Observables in our components. It makes life so much easier, but pay attention to the change detection!