As a frontend developer, you will often encounter the NgRx framework in modern Angular frontend architectures. If not, it's worth taking a look if you are building a complex web application. I will show you what NgRx is and why it is used in modern Angular frontend architectures with practical examples.
Table of contents
- What is NgRx?
- What problems does NgRx solve?
- How does NgRx work?
- When should you use NgRx?
- When should you not use NgRx?
- Are there any examples for using NgRx?
- Are there alternatives to NgRx?
What is NgRx?
According to reactive manifesto, reactive applications are:
Responsive - Responds in a timely manner if at all possible.
Resilient - Stays responsive in the face of failure.
Elastic - Can react to changes in the input rate by increasing or decreasing the resources allocated to service these inputs.
Message Driven - Rely on asynchronous message-passing to establish a boundary between components that ensures loose coupling, isolation and location transparency.
NgRx implements the Flux-Pattern. At a high level, it helps you unify all events and derive a common state in your Angular app. With NgRx, you store a single state and use actions to express state changes. It is ideal for apps with many user interactions and multiple data sources.
What problems does NgRx solve?
At a high-level, it mainly solves mainly the two main scenarios:
- Sharing data between different components
- A global state for the reuse of data
Sharing Data between different components
In a complex web application, you have different sections. Imagine the following scenario: In a web shop, you have an item list and your shopping cart. These two sections of the web shop are different component trees, probably in different Angular modules. In the item list, the user clicks on a particular item "Add to my cart". After the click, the item appears in the shopping cart.
How does this item get into the components of the shopping cart? It is necessary to exchange your data between these distancing components.
Provide a global state for reusing data
In the above example, you also do not want to load the same data twice. In this example, you want to reuse the item data like the image, item title and price in the shopping cart components, right? So there is a need for a common data store, a global state.
NgRx provides a global store and various building blocks around the store, such as Actions, Reducers, Selectors, and Effects, to manage this store as shown in the following figure:
How does NgRx work?
NgRx implements the flux pattern. The flux pattern follows the principle of having data flow in a single direction. To understand the basics of NgRx, it is worth watching the following video 👇
The following illustration shows the links between the main building blocks of NgRx:
What are Actions in NgRx?
Actions express unique events that occur while using your web application. These can be user interaction with a particular page or external interaction through network requests or direct interaction with, for example, the device API.
Actions are dispatched via Store in NgRx and observed by NgRx's Reducers and Effects.
You can define the NgRx Actions as follows:
To group actions, NgRx has introduced the ActionGroup creator. The above example can be rewritten with the ActionGroup creator to reduce boilerplate code.
What is the Store in NgRx?
The Store is the most important component of NgRx. It provides a single store to express a global, application-wide state.
The Store is based on a single, immutable data structure. The Store is also optimized for retrieving specific state data.
To access the Store, you can simply inject it. In the store, you can select data using selectors or dispatch actions.
Dispatch Actions via Store
What are Reducers in NgRx?
Reducers are responsible for state transitions from your store. The great thing is that reducers are pure functions, meaning they produce the same output for a given input.
State transition with a reducer
What are Selectors in NgRx?
Selectors give you slices of a store state. They also help you to compose different selectors.
Provide a selector to select data from the store
How to bind data from a selector in a markup?
With the @ngrx/component package you get a directive called *ngrxLet. With this directive you can easily bind data, e.g. from a selector in the markup
What are Effects in NgRx?
Effects are an RxJS based side effect model for the store. Effects use streams to provide new sources for actions. Effects isolate side effects from components. This gives us "purer" components that select state and perform actions.
Provide new sources of actions with effects
When should you use NgRx? Is NgRx worth it?
NgRx is a popular solution in the Angular ecosystem if you are building complex web applications with sophisticated state management. Characteristics of the need for NgRx are many user interactions and multiple data sources.
NgRx is a good choice, if:
- the state should be accessed by many components and services
- the state needs to be available when re-entering routes
- the state is impacted by actions from different sources.
When should you not use NgRx?
NgRx is not a good choice, if:
- you are building small Web Applications with isolated components.
- your team is not really familiar with the reactive approach.
Are there examples of how to use NgRx?
There are several live examples of the use of NgRx.
NgRx example for this blog post
Following this blog post, I have created an NgRx example that is specific to the described building blocks of NgRx. This example will help you understand how to use the NgRx framework.
The example implements a catalog and shopping cart for a web store. The catalog and shopping cart are meant to demonstrate the distant angular component trees I discussed in the section above.
It contains the following technical aspects:
- Using Store, Actions, Selectors, Reducers, and Effects in an Angular application.
- Introduction of feature stores.
- Sample tests for these NgRx elements.
In addition to Angular Framework and NgRx, it uses the following supporting frameworks & tools:
- Angular Material for the UI -stuff.
- shallow-render for reducing boilerplate test code.
- Vercel for deploying the demo application
- SonarCloud for continuous static code analysis
- GitHub Actions for running the tests.
Take a look at it 👇:
- Live Demo: https://ngrx-example.vercel.app/
- Git repository: https://github.com/bitsmuggler/ngrx-example
Example by ngrx.io
There is also an example app in the official NgRx platform repository.
This is a good example. Take a look at it 👇:
Are there alternatives to NgRx?
Not everyone likes NgRx, but the Redux concept does. For details, see this blog post about the possible reasons. There are some alternatives to NgRx 👇