DEV Community

Adam Genshaft
Adam Genshaft

Posted on • Updated on

 

NGRX | Use effects and router-store to isolate route related side πŸ§™πŸΌβ€β™‚οΈ effects

One of the major advantages of ngrx is that we can isolate side effects from the components.

When we need to have router related data on the component we'll usually use the ActivatedRoute service from the component itself. For example, we can get the id from a route using this technique:

export class MyComponent {
  id: string;
  id$ = this.activatedRoute.params.pipe(
    map(params => params.id),
    tap(id => this.id = id),
  );
}
Enter fullscreen mode Exit fullscreen mode

Let's isolate this using @ngrx/effects. The first goal is to get the route param from the URL.

How not to do it

We might be tempted to try using the ActivatedRoute service on the effects, but it's useless. It's only accessible on the "associated with a component loaded in an outlet", quoted from https://angular.io/api/router/ActivatedRoute.

Another thing we might think of is to use the Router service. But again we won't have the url parameter accessible in a clear, easy to use way.

What we can do, is to use selectRouteParam state selector from @ngrx/router-store.

Let's dive into the example. (stackblitz link at the bottom of the article)

How it's done right

Setting up the effect:

  setCurrentCourse$ = createEffect(() => this.store$.pipe(
    select(selectRouteParam('id')))
      .pipe(
        map((id: string) => setIds({id})), // dispatch a new action to set the selected id
      ),
    {dispatch: true},
  );
Enter fullscreen mode Exit fullscreen mode

Kudos for @timdeschryver for the simplified version 🀘🏼

Then our component can be as simple as:

import { Store, select } from '@ngrx/store';
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `{{selectedId$ | async | json}}`,
})
export class HomeComponent {
  selectedId$ = this.store.pipe(select((state: any) => state.featureName.selectedId));
  constructor(
    private store: Store,
  ) { }
}
Enter fullscreen mode Exit fullscreen mode

The takeaways

That a basic example showing just how to get a param. The real power comes when we need to use that param and fetch some data with it. Then we'll have an effect where we'll use the mergeMap operator to fetch the data using this id from the URL. On the component, we'll just subscribe to the fetched data, and that's it.

If you liked it, please show me some love here or on my twitter @AdamGenshaft.

Top comments (2)

Collapse
 
timdeschryver profile image
Tim Deschryver

Woo-hoo effects!
This can be made a little bit easier imho by just using the id selector as the source of the effect

 setCurrentCourse$ = createEffect(() => this.store.pipe(select(selectRouteParam('id') as any)))
  .pipe(
     map((id: string) => setIds({ id })), // dispatch a new action to set the selected id
   ), { dispatch: true });
Collapse
 
adamgen profile image
Adam Genshaft

Effects are magical, are they :)

Thanks, I agree with you so I updated the example πŸš€

11 Tips That Make You a Better Typescript Programmer

typescript

1 Think in {Set}

Type is an everyday concept to programmers, but it’s surprisingly difficult to define it succinctly. I find it helpful to use Set as a conceptual model instead.

#2 Understand declared type and narrowed type

One extremely powerful typescript feature is automatic type narrowing based on control flow. This means a variable has two types associated with it at any specific point of code location: a declaration type and a narrowed type.

#3 Use discriminated union instead of optional fields

...

Read the whole post now!