NGXS Quick Start

In this lesson we will get up and running with NGXS - a redux-style state management system for Angular. My goal in this lesson is to get you familiar with the core concepts that underpin this library and make some balanced comparisons to NgRx.

This article is a work in progress. Let me know what you think about NGXS in the comments.

NgRx vs NGXS

The big question on everybody’s mind is how does NGXS compare to NgRx?

Comparison of NgRx and NGXS for Angular State Management

Comparison of NgRx and NGXS for Angular State Management

Similarities

Both libraries…

  • use a unidirectional data flow (Redux, CQRS)
  • use a single immutable data store
  • are compatible with Redux dev tools

Differences

NGXS…

  • does not use switch-style reducers, but gives you a StateContext object to mutate the store in response to an action.
  • allows you to perform async operations within the state context (as opposed to listening to an Action stream)
  • uses a @select decorator to slice state
  • can pluck a snapshot of the state as a plain JS object
  • supports plugins

So which one is better?

There’s no right answer here. NgRx is a well-maintained and stable library with a track record in the wild, but NGXS offers significant advantages in boilerplate reduction, code readability, and extendability. Give both of them a test drive and choose the one feels right - or none at all - state management libraries are optional after all.

Store and State

Store is a global immutable object that represents your app’s entire data state tree. You change the state of the store by dispatching actions.

You will interact with the store by selecting data and dispatching actions, for instance:

// Read data as an observable
store.select('user')

// Dispatch an action to the store
store.dispatch(UpdateName);

States are classes that give you a context for modeling, selecting, and handling changes to your data.

Compared to NgRx, you can think of State as a unification of Reducers, Effects, and Selectors.

interface UserStateModel {
  name: string;
  age: number;
}

@State<UserStateModel>({
  defaults: {
    name: 'Guest',
    age: 18
  }
})
export class UserState {
  // make the magic happen here
}

Why is NGXS State an awesome concept?

NGXS addresses some of the major concerns that come with using a unidirectional data flow in Angular.

  • Improves code readability
  • Avoids Separation-of-Concerns overkill
  • Avoids boilerplate overkill
  • Integrates with Angular Dependency injection
  • Opens the door to Promises and async/await syntax
  • Avoids RxJS callback hell when dealing with side effects.
  • And lastly, improves code readability!

Actions

Actions in NGXS are very similar to NgRx, but use use a static property for the type.

export class SetUsername {
  static readonly type = 'set username';
  constructor(public payload: string) {}
}

You can handle actions inside the state class. Notice how we have a context for mutating the state, there is no need to separate this logic in a reducer and/or action stream.

export class UserState {

    @Action(SetUsername)
    addTopping(context: StateContext<SaladStateModel>, action: SetUsername) {
      const current = context.getState();
      const username = action.payload;

      context.patchState({
        username
      });
    }
}

Select and Select

The @Select() decorator is an intuitive way to slice data from the store.

@Select() user$;
@Select(state => state.user.age) age$;
@Select(UserState.getFullName) fullName$;

Inside your state, you can use the @Selector decorator to build your own slicing logic.

export class UserState {
    @Selector()
    static getFullName(user: UserStateModel) {
        return user.firstName + user.lastName;
    }
}

Questions?

Ask questions via GitHub below OR chat on Slack #questions