NgRx + Facades: Better State Management
Prior to Nx 6.2, Nx already provided scalable state management with NgRx.
Now there is a new option when generating NgRx files to also generate a facade on top of your state management… to help you work even better at-scale.
Facades are a programming pattern in which a simpler public interface is provided to mask a composition of internal, more-complex, component usages.
When writing a lot of NgRx code — as many enterprises do — developers quickly accumulate large collections of actions and selectors classes. These classes are used to [respectively] dispatch requests to- and query from- the NgRx Store.
Unfortunately — with this standard approach — each view component is required to know about many NgRx artifacts and about NgRx state management.
Using a Facade — to wrap and blackbox NgRx — simplifies accessing and modifying your NgRx state by masking internal all interactions with the
While this seems like a rather trivial change (and an extra layer), the Facade has a huge positive impact of developer productivity and yields significantly less complexity in the view layers.
Facades encourage developers to think in two (2) ways:
- Developers are encouraged to think about explicit public facade API(s).
- Developers start to think of views as presentational components that simply render data deliver from the Facade observables.
Remember these Facade observables are long-lived streams of data delivered based on queries to specific NgRx state.
Implementing our NgRx Facade
First, let’s take a look at how a Facade is implemented as a injectable service.
The facade has an explicit public API that exposes:
- public observables (e.g.
allCars$) to private queries for Store state.
- public methods (e.g.
selectCar()) that hide internals of Store usages.
View Components + NgRx
Let’s take a look at why the Facade pattern is useful… by comparing a View Component implementation with and without facades.
CarListComponent without Facades:
The simple CarListComponent definition above ^ is required to import NgRx actions, selectors, and know how to use
store.dispatch(). For more real world usages, this quickly gets complicated and messy.
CarListComponent with Facades
Developers will still leverage NgRx one-way data flows, immutable data structures,
store.select(), effects for async processing, and more… but all this is hidden from the view layer.
From a view component’s point-of-view, NgRx Facades provide a more explicit public API and less moving parts.
Even better, Facades can inject and use other facades!
With Facades, writing state-dependent view components is much easier. To get hands-on with NgRx facades, check out this StackBlitz demo or use the Nx Schematic
ngrx to generate your own NgRx files!
Testing NgRx Facades
Using async/await techniques and mock services, developers can easily test the Facade’s public API.
ngrxschematics will also generate a
cars.facade.spec.ts shown below:
In the above test class, we are asynchronously testing:
allCars$properties by directly dispatching a `CarsLoaded` action and bypassing any similar functionality in the
loadAll()public method using a the standard `LoadCars` action dispatched to the NgRx store.
- using the Nx utility method
readFirstto read a single value from the target observable.
await toto ensure our testing and and the resulting output responses match an expected sequence. Note the try/catch used to delegate the error handling to
Note, if the
cars.effects.tsimplementation internal used a
cars.http.service.tsclass, we could — in our test — register a mockup HttpService to simulate the handling a
NgRx Facades with Nx Schematics
Use the latest Nx schematics to create both your NgRx generated files and an associated Facade implementation.:
# See help for the `ngrx` schematic
# Use the '-d' option to test in dryRun mode if desired.
ng g ngrx -h
# Generate ngrx files + facade in the 'cars' library
ng g ngrx cars --module=libs/cars/src/lib/cars.module.ts --facade -d
By default the facade classes are not generated with
ng g ngrx; use the
facadeflag to include scaffolding for Facades.