NgRx Facades: Pros and Cons

Learn about the facade pattern, why you may or may not want to use one with NgRx, and how to create a facade.

1 Like

How did you like this post? Please share any comments or feedback with us on this thread :slight_smile:

Facades encapsulate the complexity of using and combining NgRx Selectors (aka queries). The beauty of NgRx Facades, however, is how it enables code compression in the view layers.

The books-page.component.ts can easily be compressed to this:

@Component({
  selector: 'abl-books-page',
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `

    <mat-card>
      <mat-card-title>My Collection</mat-card-title>
      <mat-card-actions>
        <button mat-button raised color="accent" (click)="facade.loadBooks()">Reload Books</button>
      </mat-card-actions>
    </mat-card>

    <abl-book-preview-list [books]="books$ | async"></abl-book-preview-list>
})
export class BooksPageComponent implements OnInit {
  books$: Observable<Book[]> = this.facade.allBooks$;

  constructor(private facade: BooksFacadeService) {  }
}

See my Gist for more details: Compressing View Logic with Facades · GitHub

1 Like

That’s great! Thanks for your input Thomas!

I’m not sure I agree that using facades is a productivity win. It’s takes time to write and maintain all that extra code for each of your stores, and since your facade’s methods should be a simple mapping to your store’s selectors and actions (if you’re putting a lot of logic inside facade methods, something’s gone wrong) then you’re not saving much effort using the facade’s method vs. calling the store directly in your components. E.g. this.myFacade.fetchData(); isn’t really much less typing than this.store.dispatch(new FetchDataAction());. Overally, it’s more likely to be a productivity loss, as you have more code to write, maintain and navigate, and for new developers to grok when coming to the project.

The only legitimate argument I see for facades is abstracting away your use of NgRx from your components. Personally, I don’t find that convincing enough. If you’re doing things right in an NgRx app, your components should be extremely dumb, as all your logic should be happening in your reducers, selectors and effects. Your components become little more than a thin bridge between the HTML in the template and the store. As such, their existence and implementation depends entirely on your use of NgRx and it’s not as if you can stop using NgRx and keep using these components. Nor it is the case that there are genuine alternative Redux implementations that you’re potentially going to use in an Angular app.

Thanks for reading and for your input, Jon!

1 Like

We use the facade pattern, simply because it makes testing easier. When you’re testing the component mocking the store starts becoming messy but by using the facade pattern all you need to do is mock the actual service itself which makes testing significantly easier.

However we do expose a disptach() method that’s used by all of our facade services that the component uses to dispatch actions to the store, so all we’re really doing is putting the facade in between the store and its selectors

1 Like

I am a big fan of the facade pattern and it is implementation
Yes everyone can agree that it adds more code than it saves but as a new learner of NGRX having a facade service is a lot easier to interact with than the other seven ngrx files.
One big impediments I surprisingly faced and couldn’t solve in time was this:
while unit testing the page component’s dispatch function the Books$ property should update accordingly.
the unit test expected that the service.dispatch should be called but I couldn’t expect on the Books$ changes. This change should go through the store so that was hard to implement

Welcome to the community, @mdavid19995! That’s an interesting point. How did you end up implementing the test?

Thanks Sam!
unfortunately I didn’t implement it and had direction from my manager to remove the Facade because it adds that extra layer of testing
One point to mention is that I believe I didn’t do a good job in mocking my store to behave right.

Also, even if I am in the same component and an action dispatch should change another property on my component(the one that is equal to my facade selector), this seems to be a little outside the scope of a unit test. It is like a super unit test and that is why I kinda give up on it.
Again I love the facade pattern and other than this testing issue I think it is brilliant but I would love to hear others opinions on this matter

Thanks

1 Like

I came to facades pattern after deciding that i want to abstract the data access from the store, so that the component doesn’t care from where the data comes and goes. Another benefit from this abraction is that you could easily replace ngrx with Mobx or Akita. I’m curious how would be implemented a parametrized selector with facades?

Hi @zlati.pehlivanov, welcome to the Auth0 Community!

I’m not sure what you mean – like a selector where you pass in something such as an id?

Cheers,
Sam Julien

@sam.julien yes exactly

So, my understanding is that the best practice with parameterized selectors is to dispatch an action with the parameter in it and have a selector that gets it from the store. From an article by Tim Deschryver:

Action:

this.store.dispatch(new SelectCustomer(customer.id))

Selector for the selected customer id:

export const selectSelectedCustomerId = createSelector(
  selectCustomerEntities, 
  fromCustomers.selectedCustomerId
);

Composed selector for the selected customer:

export const getSelectedCustomer = createSelector(
  selectCustomers,
  selectSelectedCustomerId,
  (customers, selectedId) => customers[selectedId]
);

Which would make the use case like so:

this.customer = store.pipe(
  select(customers.getSelectedCustomer)
);

Then, in a facade, you’d have a function to dispatch the SelectCustomer action and you’d have an observable for that selector:

selectedCustomer$ = this.store.pipe(
  select(customers.getSelectedCustomer)
);

selectCustomer(customerId: number) {
  this.store.dispatch(new SelectCustomer(customerId));
}

(This is all using pre-NgRx 8 syntax so of course you’d want to adjust for createAction.)

What do you think?

Cheers,
Sam Julien

Right, but in this case we are not preselcting an entity but we still want to get a specific entity.
in the end, My way of doing is

specificCustomer$(id) = this.store.select(customers.getSpecificCustomer(id))

myobs$ = this.facade.specificCustomer$(id);

1 Like

Cool approach @zlati.pehlivanov!

3 Likes

Can we get data from selectors instantly?

I’ve an issue with the selectors subscribe multiple time. i.e: First time I call API to create Session, it return undefined and new Session A; I call create one, it return Session A then Session B. I just need to get the latest result when calling API as Promise but I was stuck. Please help me. Thanks in advance!

Hey @duyvt92, thanks for your question. Do you have some code or a StackBlitz you could share that I could take a look at?

1 Like