Getting started with NGXS

Maureen Heitzmann
Pictet Technologies Blog
7 min readJun 3, 2021

As your Angular app is getting more and more complex, you realise that you need a common storage space in order to easily save & share information and make it available to all components. NGXS could be the library you want to use, and this article will show you how.

N.B: Sources of the example presented in this tutorial are available here:

Summary

Here are the different topics that we will cover in this article:

  1. What is NGXS?
  2. What are the important concepts of NGXS?
  3. How are the different concepts organised?
  4. How to setup NGXS?
  5. How to use NGXS in practice?
  6. How can I easily see the State logs?
  7. Conclusion

What is NGXS?

NGXS is a State Management library for Angular just like NgRx or Akita, the difference being that NGXS is intended to be simpler to understand and use. Indeed, it reduces boilerplate code as much as possible and uses modern TypeScript features such as classes and decorators.

What are the important concepts of NGXS?

Before installing NGXS in your app, there are key notions that you should understand first:

State

The State is an immutable class preceded by the @State annotation in which information shared between several components of our application will be stored.

It is defined in this way:

The @State annotation allows us to define the model of the State.

If you have several States in your application, each State model must have a different name, stored in the field name, as in the example.

The defaults field is used to define the initial state of your State.

Store

The Store contains the State. It offers both the possibility to dispatch Actions which will modify the State and to select information stored in the State.

Actions

Actions are defined as follows:

The type constant is mandatory in each action; it is used as the identifier in the Action and, consequently, it must have a unique value within the whole application. Best practice here is to define these identifiers like this: [Resource] description of the action as in the example.

In the constructor(), we find the data of the Action. If the Action does not need data, it becomes optional to declare the constructor.

Once the Action has been dispatched from a component, the associated code will be executed in order to modify the data stored in the State.

Select

Select is used from a component to get a value stored in the State in the manner of a listener on an Observable; i.e. the select value will be automatically updated when the value of the associated variable in the state is modified.

There are several ways to use a Select:

  • With an annotation:
@Select(TodoState.getTodoList) todoList$?: Observable<string[]>;
  • By calling the function of the store:
this.store.select(TodoState.getTodoList)
.subscribe(myTodoList => this.todoList = myTodoList);

In both cases, Select takes a function as a parameter which is called a Selector. The role of this function is to act as a decorator by allowing the program to execute some custom code, like a filter or a sort for example, when we get the listened value from the State.

How are the different concepts organised?

Now that you are more familiar with the different concepts of NGXS, let’s look at how they interact with each other. For this, there is nothing better than a schema.

Schema explaining NGXS functioning

It’s quite simple, isn’t it? Okay, I’m helping you out a little … :)

Here are the different steps illustrated by this diagram:

  1. All start in the C1 component; this one dispatches an Action.
  2. The action modifies the state of the State.
  3. As components C1 and C2 both listen to the same State element through the Select, they will automatically retrieve the new updated value.

That’s it for the theoretical part. Let’s move on to practice now.

How to set up NGXS?

Now that you have a good grasp of NGXS’ theory, it is time to explain how to install it in your Angular application. For this, there is nothing simpler, you just need to use the following command:

npm install @ngxs/store --save

Or if you are using yarn:

yarn add @ngxs/store

Finally, add the following code in the imports of the @NgModule:

NgxsModule.forRoot([TodoState], {
developmentMode: !environment.production
}),

Like this:

Note: If you want to use several States in your Angular module, you have to list them all in the NgxsModule.forRoot().

How to use NGXS in practice?

First of all, we need an example, so let’s implement a small todo list application in which only two actions are possible:

  • Adding an item to the list,
  • Emptying the list.

To have a better representation, here is an excerpt showing the different features:

Video showing the features of the application used as example for this tutorial

If you have not done so yet, I encourage you to download the git project that uses the example in this article, so you can easily navigate between the different files while following the explanations below.

As we saw previously in the theoretical part, everything starts in a component, so let’s start to write the app.component.ts:

Here newTodo is linked to the input while onAddTodo() and onEmptyList() are linked to the two actions buttons of the UI.

Now, when we press our buttons, we would like to trigger Actions that will change the State. This is the role of the dispatch function provided by the Store. We adapt our code, and it becomes:

Let’s create the Actions in the todo.actions.ts:

As addTodo takes the new todo as input, we need to declare the constructor with newTodo as a parameter.

Some code will then be executed following the triggering of these Actions in order to modify the State. This is where the todo.state.ts file comes in:

@State allows us to define the initial state of the State.

The functions preceded by the @Action annotation are, as the name implies, linked to an Action, and will be executed when these ones are triggered.

Let’s look in greater detail at the more complex addTodo() function, in order to understand the elements that make it up.

First, this one takes 2 parameters:

  • {patchState, getState}: StateContext<TodoStateModel> which provides us with patchState() and getState() — two functions that will allow us to interact with the State defined in the same file.
  • {newTodo}: AddTodo which enables us to get data of the triggered Action.

As explained before, the State is immutable. To modify the value of one or more elements of the State, NGXS offers a patchState() function used as follows in our example:

patchState({todoList: [...getState().todoList, newTodo]});

This function allows the developer to provide parameters for only the fields he wishes to modify without having to make a copy of the whole State.

Now, as we want our component to access the todoList value from the State, we need to add a fancy getter function; so, todo.state.ts becomes:

As you can see, we added the getTodoList() function which takes the State as parameter, and it is preceded by @Selector() annotation.

Each time the value of todoList changes, the code of the Selector function is executed and the component which listens to todoList through getTodoList() will automatically receive the updated value.

We also saw previously that this function acts as a decorator for the returned value; therefore if you decide to sort todoList in alphabetical order in the Selector, each component which listens to todoList through this function will receive the sorted list.

Finally, to complete the loop what we still need to do is to come back in our App component to allow it to access the value of todoList from the State thanks to the Selector we just created. For that, we add a new variable in our component preceded by the @Select() annotation with the Selector function as parameter.

So, here is the final version of app.component.ts:

We have now implemented all the steps we needed to store a value in the State and to get this value from the component.

How can I easily see the State logs?

There is a plugin you can add to your application to see in the browser console the state of the State after each dispatched Action: it is called NGXS Logger Plugin. Let’s install it:

npm install @ngxs/logger-plugin --save

Or if you are using yarn:

yarn add @ngxs/logger-plugin

Now, we just have to add the module to our imports in the @NgModule of our application like this:

And that’s it! Now, to each Action dispatched you can see values stored in the State before and after the Action is performed. Here is an example after clicking on “Add Todo” and then on “Empty List”:

Conclusion

Congratulations, you now know how to set up and use NGXS; your next mission — should you choose to accept it — will be to adapt the example we have seen together to the needs of your project.
If you want more information about NGXS, you can find the official documentation HERE.

Also, do not hesitate to inquire about NGXS compatible plugins, as they can greatly facilitate the life of the developer. In this article we presented NGXS Logger Plugin, but there are many others like for example Select-Snapshot which includes a @SelectSnapshot()annotation that you can use instead of the @Select()annotation and which allows you to directly retrieve the current state value instead of an Observable.

About me

I have been Junior Software Developer at Pictet Technologies for one year and half. My goal in writing this article is to synthesise my knowledge about NGXS and to share it with those keen to know more about this topic.
I would also like to thank my benevolent colleagues who helped me during the review phase of this article. :)

--

--