Angular State Management with NGXS

Sem EkkelboomSem Ekkelboom
5 min read

Table of contents

What is state?

In Angular, you are not able to build complex applications without managing state. State is all the data and application logic that makes the UI work as it should. This can be data to visually show in the UI, state to keep track if certain buttons must be enabled or what components of the application can or cannot be visible to the user.

What is state management?

State management is the concept that handles the application state in a certain way. This can be as simple or as complex as your application requires. In Angular, we can use simple services to handle very specific application state. For example, we could use a user service in our application that keeps track of the signed-in user, when the logged-in user is expired, and make sure the username is available throughout the entire application. Although this is a viable option, it is not always the best solution for every type of state. But what is?

What types of state do we deal with?

We can define four different types of state to be managed:

  • Router State: think about URL parameters and the information our route gives us. This is handled by the Angular router.

  • Component State: State that handles the component-specific logic, like which elements are being shown, which items are selected, etc. This state can be easily handled within the component itself as it is not going to affect another component.

  • Persisted State: state that is being remembered when navigating between different pages. Think about showing a different menu when the user is signed in. This logic would be perfect to put in an Angular Service. If the service becomes too complex, however, it would be wise to use a state management Framework like NGXS.

  • Shared State: state that needs to be shared between different parts of our web application. This data should be kept on our application's higher level and used by different components. In this case, we would use a state management framework based on the Redux pattern like NGXS to keep track of the state in an application store.

Why use state management?

Managing data in your application gets more and more important nowadays. You do not want to do an API request every time a user switched pages if nothing has changed on the back-end, calling multiple services to combine the data you need and losing track of which service triggers which change in your application. Not using a managed state can create a web of services where we lose track of which part of the application handles which state logic.

Unmanaged state with Angular services only: without ngxs.png

Keeping the data and application logic managed within an application store, the bundle of controlled state, allows you to have one single source of truth. Data-flows through your application get a lot less complex when the logic is not spread out over multiple services but neatly bundled in a well-designed store.

Managed state with NGRX: with ngxs.png

What is NGXS?

NGXS is such a state management framework. It tries to make state management simple and accessible for everyone. A common problem in using state management is the amount of boilerplate code needed to set up your store. NGXS focuses on reducing boilerplate code and minimizes the amount of RxJs code needed to work with the state. Useful if you haven’t worked with RxJs a lot. NGXS also makes use of Dependency Injection meaning Angular services can be injected into the state to make use of more Angular features.

Actions in NGXS are asynchronous, meaning we can continue our application logic while our store handles all the state management in the meantime. We can listen for specific action states, for instance when one of our dispatched actions to fetch the latest users from our API is handled successfully, we can select this data from the store and update our user list in the UI accordingly. The four action states we can use are: DISPATCHED, ERRORED, CANCELED , and SUCCESSFUL.

action states.png

Why use NGXS?

But why use NGXS and not an alternative state management framework NGRX? Let’s first say that both have their pros and cons and choosing one does not mean the other isn’t a great option as well. One of the biggest advantages of NGXS is that it has way less boilerplate code as I said before. State logic is written in a single State class, while NGRX users reducers for state changes and effects for handling side-effects. This means you write more code and the code can be more complex. The advantage of NGRX however is that complex logic is split into multiple files where actions in NGXS contain both the NGRX reducer and side effects.

Example of NGXS in practice:

What a managed state could look like for your application is totally up to you, but below I’ve placed an example of a very simple but elegant managed user state.

users.actions.ts

// NGXS Action Type
export class FetchUsers {
  static type = '[Users] Fetch users';
}

users.state.ts

// NGXS State Model
export interface UsersStateModel {
  users: User[];
}

// NGXS State
@State<UsersStateModel>({
  name: 'users',
  defaults: {
    users: []
  }
})

// NGXS State Class
@Injectable()
export class UsersState {
  constructor(private usersService: UsersService) {}

  // NGXS Action
  @Action(FetchUsers)
  getUsers(ctx: StateContext<User[]>) {
    return this.usersService.fetchUsers().pipe(
      tap(users => {
        ctx.patchState({ users });
      })
    );
  }

  // NGXS Selector
  @Selector()
  static getUsers(state: UsersStateModel) {
    return state.users;
  }
}

In this example, we have one action to fetch all the users from our API using our dedicated UsersService. All components in our application that want to use our list of users, can easily use the NGXS Selector getUsers to read them from the store. We could go even further and handle the code that would wait for the Action type SUCCESSFUL to be triggered and then get the users from the store, but I'll leave that up to you as a little exercise!

Now it's your turn

Using NGXS is a great way to manage complex application state for your Angular applications without the hassle of too much boilerplate code. It makes your shared application state manageable for your entire application. Did I manage to get you interested in using NGXS? Let me know what cool stuff you've built with NGXS!

10
Subscribe to my newsletter

Read articles from Sem Ekkelboom directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Sem Ekkelboom
Sem Ekkelboom