NgRx Feature Creator

Cover photo by Sigmund on Unsplash.

The createFeature function is introduced in NgRx v12.1.
It reduces repetitive code in selector files by generating a feature selector and child selectors for each feature state property. It’s inspired by the ngrx-ch…


This content originally appeared on DEV Community and was authored by Marko Stanimirović

Cover photo by Sigmund on Unsplash.

The createFeature function is introduced in NgRx v12.1.
It reduces repetitive code in selector files by generating a feature selector and child selectors for each feature state property. It's inspired by the ngrx-child-selectors library.

NgRx Feature

There are three main building blocks of global state management with @ngrx/store: actions, reducers, and selectors. For a particular feature state, we create a reducer for handling state transitions based on the dispatched actions, and selectors for obtaining slices of the feature state. Also, we need to define a feature name needed to register the feature reducer in the NgRx store. Therefore, we can consider the NgRx feature as a group of feature name, feature reducer, and selectors for the particular feature state. Let's now look at the "traditional" way of creating the NgRx feature.

To create a reducer there is the createReducer function from the @ngrx/store package:

// books.reducer.ts
import { createReducer } from "@ngrx/store";

import * as BookListPageActions from "./book-list-page.actions";
import * as BooksApiActions from "./books-api.actions";

export const featureName = "books";

export interface State {
  books: Book[];
  loading: boolean;
}

const initialState: State = {
  books: [],
  loading: false,
};

export const reducer = createReducer(
  initialState,
  on(BookListPageActions.enter, (state) => ({
    ...state,
    loading: true,
  })),
  on(BooksApiActions.loadBooksSuccess, (state, { books }) => ({
    ...state,
    books,
    loading: false,
  }))
);

To register this reducer in the NgRx store, we use the StoreModule.forFeature method:

// books.module.ts
import { StoreModule } from "@ngrx/store";

import * as fromBooks from "./books.reducer";

@NgModule({
  imports: [
    StoreModule.forFeature(fromBooks.featureName, fromBooks.reducer),
  ],
})
export class BooksModule {}

To select the state from the store, let's create a feature selector, child selectors, and also a view model selector:

// books.selectors.ts
import { createFeatureSelector, createSelector } from "@ngrx/store";

import * as fromBooks from "./books.reducer";

// feature selector
export const selectBooksState = createFeatureSelector<fromBooks.State>(
  fromBooks.featureKey
);

// child selectors
export const selectBooks = createSelector(
  selectBooksState,
  (state) => state.books
);
export const selectLoading = createSelector(
  selectBooksState,
  (state) => state.loading
);

// view model selector
export const selectBookListPageViewModel = createSelector(
  selectBooks,
  selectLoading,
  (books, loading) => ({ books, loading })
);

Using Feature Creator

Let's now look at how to achieve the same result by using the createFeature function. We will first refactor the reducer file:

// `createFeature` is imported from `@ngrx/store`
import { createFeature, createReducer } from "@ngrx/store";

import * as BookListPageActions from "./book-list-page.actions";
import * as BooksApiActions from "./books-api.actions";

interface State {
  books: Book[];
  loading: boolean;
}

const initialState: State = {
  books: [],
  loading: false,
};

// feature name and reducer are now passed to `createFeature`
export const booksFeature = createFeature({
  name: "books",
  reducer: createReducer(
    initialState,
    on(BookListPageActions.enter, (state) => ({
      ...state,
      loading: true,
    })),
    on(BooksApiActions.loadBooksSuccess, (state, { books }) => ({
      ...state,
      books,
      loading: false,
    }))
  ),
});

Registering the feature reducer in the store can now be done by passing the entire feature object to the StoreModule.forFeature method:

// books.module.ts
import { StoreModule } from "@ngrx/store";
import { booksFeature } from "./books.reducer";

@NgModule({
  imports: [StoreModule.forFeature(booksFeature)],
})
export class BooksModule {}

Finally, let's see what the selector file looks like:

// books.selectors.ts
import { createSelector } from "@ngrx/store";
import { booksFeature } from "./books.reducer";

export const selectBookListPageViewModel = createSelector(
  booksFeature.selectBooks,
  booksFeature.selectLoading,
  (books, loading) => ({ books, loading })
);

The previously manually created feature and child selectors are now removed because createFeature generates them for us. All generated selectors have the "select" prefix and the feature selector has the "State" suffix.

In this example, the name of the feature selector is selectBooksState, where "books" is the feature name. The names of the child selectors are selectBooks and selectLoading, based on the property names of the books feature state.

Conclusion

Feature creators reduce repetitive code in selector files by using the power of template literal types introduced in TypeScript v4.1. It could bring big improvements to your code, especially with huge feature states.

Resources

Peer Reviewers

Thank you Tim for giving me helpful suggestions on this article!


This content originally appeared on DEV Community and was authored by Marko Stanimirović


Print Share Comment Cite Upload Translate Updates
APA

Marko Stanimirović | Sciencx (2021-09-14T12:42:02+00:00) NgRx Feature Creator. Retrieved from https://www.scien.cx/2021/09/14/ngrx-feature-creator/

MLA
" » NgRx Feature Creator." Marko Stanimirović | Sciencx - Tuesday September 14, 2021, https://www.scien.cx/2021/09/14/ngrx-feature-creator/
HARVARD
Marko Stanimirović | Sciencx Tuesday September 14, 2021 » NgRx Feature Creator., viewed ,<https://www.scien.cx/2021/09/14/ngrx-feature-creator/>
VANCOUVER
Marko Stanimirović | Sciencx - » NgRx Feature Creator. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/09/14/ngrx-feature-creator/
CHICAGO
" » NgRx Feature Creator." Marko Stanimirović | Sciencx - Accessed . https://www.scien.cx/2021/09/14/ngrx-feature-creator/
IEEE
" » NgRx Feature Creator." Marko Stanimirović | Sciencx [Online]. Available: https://www.scien.cx/2021/09/14/ngrx-feature-creator/. [Accessed: ]
rf:citation
» NgRx Feature Creator | Marko Stanimirović | Sciencx | https://www.scien.cx/2021/09/14/ngrx-feature-creator/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.