Announcing NgRx v14: Action Groups, ComponentStore Lifecycle Hooks, ESLint package, Revamped NgRx Component, and more!
Tags: angular, ngrx, opensource, webdev
Published: 2022-06-20 15:21:35



We are pleased to announce the latest major version of the NgRx framework with some exciting new features, bug fixes, and other updates.

---

## New Function to Create Action Groups 🧙

If you're familiar with NgRx Store, you know that actions are an important part of the application that uses it. Some might say actions are the gluten of the NgRx loaf 😉, but that's a story for another day. In NgRx 13.2, we introduced the new `createActionGroup` function that was initially thought of by [Mike Ryan](https://twitter.com/MikeRyanDev/status/1307687779195854849?s=20&t=2BA7Dd9a3LlDNXYlDTfY2A) and implemented by [Marko Stanimirović](https://twitter.com/MarkoStDev) as a way to make creating actions even easier. 

The video below gives a quick overview of writing actions separately with Good Action Hygiene™, and introduces the new `createActionGroup` function to minimize the amount of code to write and export groups of actions.

{% youtube rk83ZMqEDV4 %}

The `createActionGroup` function makes use of more advanced features that have been introduced in TypeScript, so if you're into advanced TypeScript, definitely check out the [source code](https://github.com/ngrx/platform/blob/master/modules/store/src/action_group_creator.ts) to find some new tricks there.

---

## Component Store Lifecycle Hooks 🎣

The [NgRx ComponentStore](https://ngrx.io/guide/component-store) library has been gaining popularity because of its features to manage state reactively in Angular applications more consistently and predictably. Using ComponentStore allows you to abstract away the business logic out of your components when update state, performing side effects, and providing observable streams of state changes. 


There are some use cases where you need to perform some task when the ComponentStore is created, or when the ComponentStore state is first initialized. Previously to do this, you had to expose some method on the ComponentStore and call it from the Component's lifecycle method. To simplify this, we've introduced two interfaces and lifecycle hooks for ComponentStore, `OnStoreInit` and `OnStateInit`.

### OnStoreInit

The `OnStoreInit` interface is used the implement the `ngrxOnStoreInit` method in the ComponentStore class. This lifecycle method is called immediately after the ComponentStore class is instantiated.

```ts
export interface BooksState {
  collection: Book[];
}

export const initialState: BooksState = {
  collection: []
};

@Injectable()
export class BooksStore extends ComponentStore<BooksState> implements OnStoreInit {

  constructor() {
    super(initialState);
  }

  ngrxOnStoreInit() {
    // called after store has been instantiated
  }
}
```

And use the `provideComponentStore()` function to register the ComponentStore in the `providers` array.

```ts
@Component({
  // ... other metadata
  providers: [
    provideComponentStore(BooksStore)
  ]
})
export class BooksPageComponent {
  constructor(private booksStore: BooksStore) {}
}
```

### OnStateInit

The `OnStateInit` interface is used the implement the `ngrxOnStateInit` method in the ComponentStore class. This lifecycle method is called **only once** after the ComponentStore state is initially set. ComponentStore supports eager and lazy initialization of state, and the lifecycle hook is called appropriately in either scenario.

### Eager State Init

```ts
export interface BooksState {
  collection: Book[];
}

export const initialState: BooksState = {
  collection: []
};

@Injectable()
export class BooksStore extends ComponentStore<BooksState> implements OnStateInit {
  constructor() {
    // eager state initialization
    super(initialState);
  }

  ngrxOnStateInit() {
    // called once after state has been first initialized
  }
}
```

```ts
@Component({
  // ... other metadata
  providers: [
    provideComponentStore(BooksStore)
  ]
})
export class BooksPageComponent {
  constructor(private booksStore: BooksStore) {}
}

### Lazy State Init


export interface BooksState {
  collection: Book[];
}

@Injectable()
export class BooksStore extends ComponentStore<BooksState> implements OnStateInit {
  constructor() {
    super();
  }

  ngrxOnStateInit() {
    // called once after state has been first initialized
  }
}

export const initialState: BooksState = {
  collection: []
};
```

```ts
@Component({
  // ... other metadata
  providers: [
    provideComponentStore(BooksStore)
  ]
})
export class BooksPageComponent implements OnInit {
  constructor(private booksStore: BooksStore) {}

  ngOnInit() {
    // lazy state initialization
    this.booksStore.setState(initialState);
  }
}
```

If you implement the lifecycle hooks in the ComponentStore, and register it with `providers` without using `provideComponentStore()`, in development mode, a warning is logged to the browser console.

---

## Native ESLint package 📦

The NgRx team has always been looking at better ways to encourage developers to use best practices when using NgRx libraries. Team member [Tim Deschryver](https://twitter.com/tim_deschryver) created the `ngrx-eslint-plugin` package to provide ESLint rules for best practices for applications built with NgRx. In a previous version of NgRx, we introduced adding the `ngrx-eslint-plugin` package to your `package.json`, and adding lint rules to your ESLint configuration. 

```sh
ng add @ngrx/store
```

To provide a more integrated experience, we've moved the `ngrx-eslint-plugin` package into the main `ngrx/platform` repository, and have added a new `@ngrx/eslint-plugin` package for the ESLint rules. The package has already been stable for a while, and will now be more visible to developers using NgRx libraries with already available docs pages and ongoing support.

---

## NgRx Component package overhauled ✍

The NgRx Component package has always had an ambitious goal, with that being a way to bring more reactivity to templates in Angular, along with providing support for fully zone-less Angular applications. Initially written by [Michael Hladky](https://twitter.com/Michael_Hladky), and ultimately turning into the `@rx-angular/template` library, `@ngrx/component` has been well received even while still being an experimental package. 

NgRx Component provides two main features, the `ngrxPush` pipe and `ngrxLet` directive for more easily using observables in Angular component templates. For version 14, team member [Marko Stanimirović](https://twitter.com/MarkoStDev) has completely rewritten the component package from the ground up to provide a more consistent way to handle observable and static data, improved performance for zone-less applications in Angular, and more.

NgRx Component also introduces two new modules: `LetModule` and `PushModule`. 

To use the new modules, import and add the `LetModule` or `PushModule` to the `imports` array in your standalone component or NgModule. 

```ts
import { Component } from '@angular/core';
import { LetModule, PushModule } from '@ngrx/component';
 
@Component({
  // ... other metadata
  standalone: true,
  imports: [
    // ... other imports
    LetModule,
    PushModule
  ],
})
export class MyStandaloneComponent {}
```

These new NgModules allow for more granular usage of the `ngrxPush` pipe and `ngrxLet` directive, and paves the way to introduce standalone versions of these pipes and directives to take more advantage of the new standalone features introduced in Angular v14. Read [this post](https://dev.to/ngrx/building-reactive-angular-templates-with-ngrx-component-4m1e) to learn more about the NgRx Component updates in v14.

---

## The future of NgRx in Angular 🌞

Angular v14 has introduced some exciting new features for components, pipes, and directives, a new "environment injector", and an updated `inject()` function for using Dependency Injection without directly using a constructor. The standalone features for components, pipes, and directives allow you to build Angular applications with NgModules primarily being optional. 

As most NgRx libraries primarily are sets of providers, and don't provide UI components, this allows us to take a fresh look with these new standalone APIs to register NgRx providers in Angular applications without NgModules. Check out [Marko's latest blog post](https://dev.to/ngrx/using-ngrx-packages-with-standalone-angular-features-53d8) on using NgRx in Angular with standalone features. The `inject()` function has been around for a while, but now provides expanded capabilities for composing functions that have access to inject dependencies without the constructor, and easier composition of extended classes.

While Angular standalone features are still in developer preview, we have proposed some new APIs for NgRx in our [latest RFC](https://github.com/ngrx/platform/discussions/3399). If you would like to have some input on future Angular applications built with NgRx, feel free to check out the RFC and share your thoughts.

---

Swag store and Discord Server! 👕

You can get official NgRx swag through our [store](https://ngrx.threadless.com)! T-shirts with the NgRx logo are available in many different sizes, materials, and colors. We will look at adding new items to the store such as stickers, magnets, and more in the future. Visit our store to get your NgRx swag today!

Join our [discord server](https://discord.gg/ngrx) for those who want to engage with other members of the NgRx community, old and new. 

---

## Deprecations and Breaking Changes 💥

This release contains bug fixes, deprecations, and breaking changes. For most of these deprecations or breaking changes, we've provided a migration that automatically runs when you upgrade your application to the latest version.

Take a look at the [version 14 migration guide](https://ngrx.io/guide/migration/v14) for complete information regarding migrating to the latest release. The complete [CHANGELOG](https://github.com/ngrx/platform/blob/master/CHANGELOG.md) can be found in our GitHub repository.

---

## Upgrading to NgRx 14 🗓️

To start using NgRx 14, make sure to have the following minimum versions installed:

- Angular version 14.x
- Angular CLI version 14.x
- TypeScript version 4.7.x
- RxJS version ^6.4.x or RxJS version ^7.5.x

NgRx supports using the Angular CLI ng update command to update your NgRx packages. To update your packages to the latest version, run the command:

```sh
ng update @ngrx/store
```

---

## Contributing to NgRx 🥰

We're always trying to improve the docs and keep them up-to-date for users of the NgRx framework. To help us, you can start contributing to NgRx. If you're unsure where to start, come take a look at our contribution guide and watch the introduction video Jan-Niklas Wortmann and Brandon Roberts have made to help you get started.

Thanks to all our contributors and sponsors

NgRx continues to be a community-driven project. Design, development, documentation, and testing all are done with the help of the community. We've recently added a community section to the NgRx team page that lists every person that has contributed to the platform.

If you are interested in contributing, visit our GitHub page and look through our open issues, some marked specifically for new contributors. We also have active GitHub discussions for new features and enhancements.

---

## Sponsor NgRx 💲

We are looking for our next **Gold** sponsor, so if your company wants to sponsor the continued development of NgRx, please visit our [OpenCollective](https://opencollective.com/ngrx) page for different sponsorship options, or contact us directly to discuss other sponsorship opportunities.

We want to give a big thanks to our Silver sponsor, Narhwal Technologies! Nrwl has been a longtime promoter of NgRx as a tool for building large Angular applications, and is committed to supporting open source projects that they rely on for Nx.

Follow us on [Twitter](https://twitter.com/ngrx_io) for the latest updates about the NgRx platform.