DEV Community

Alfredo Perez
Alfredo Perez

Posted on

NGRX Workshop Notes - Reducers

  • Produce new states
  • Receive the last state and next action
  • Switch on the action type
  • Use pure, immutable operations

Notes

  • Create separate reducer per feature
  • Should live outside the feature because the state it is shared in the whole application
  • State should save the model as it comes from the API. This can be later transformed into the selectors.
  • Combine actions that can use the same reducer
  on(BooksPageActions.enter, BooksPageActions.clearSelectedBook, (state, action) => ({
          ...state,
          activeBookId: null
   })),
Enter fullscreen mode Exit fullscreen mode
  • Only reducers can modify state and it should do it in an immutable way
  • Create helper functions to handle the data manipulation of collections.

Example

const createBook = (books: BookModel[], book: BookModel) => [...books, book];
const updateBook = (books: BookModel[], changes: BookModel) =>
    books.map(book => {
        return book.id === changes.id ? Object.assign({}, book, changes) : book;
    });
const deleteBook = (books: BookModel[], bookId: string) =>
    books.filter(book => bookId !== book.id);

...

    on(BooksApiActions.bookCreated, (state, action) => {
        return {
            collection: createBook(state.collection, action.book),
            activeBookId: null
        };
    }),
    on(BooksApiActions.bookUpdated, (state, action) => {
        return {
            collection: updateBook(state.collection, action.book),
            activeBookId: null
        };
    }),
    on(BooksApiActions.bookDeleted, (state, action) => {
        return {
            ...state,
            collection: deleteBook(state.collection, action.bookId)
        };
    })
Enter fullscreen mode Exit fullscreen mode

Feature reducer file

  • Declares a State interface with the state for the feature
  • Declares an initialState that included the initial state
  • Declare a feature reducer that contains the result of using createReducer
  • Exports a reducer function that wraps the reducer created. This is needed for AOT and it is not needed when using Ivy.

Example

export interface State {
    collection: BookModel[];
    activeBookId: string | null;
}

export const initialState: State = {
    collection: [],
    activeBookId: null
};

export const booksReducer = createReducer(
    initialState,
    on(BooksPageActions.enter,
        BooksPageActions.clearSelectedBook, (state, action) => ({
        ...state,
        activeBookId: null
    })),
    on(BooksPageActions.selectBook, (state, action) => ({
        ...state,
        activeBookId: action.bookId
    })),
);

export function reducer(state: State | undefined, action: Action) {
    return booksReducer(state, action);
}

Enter fullscreen mode Exit fullscreen mode
  • The index file defines the state and assigns each reducer to a property on the state
import * as fromBooks from "./books.reducer";

export interface State {
    books: fromBooks.State;
}

export const reducers: ActionReducerMap<State> = {
    books:fromBooks.reducer
};

export const metaReducers: MetaReducer<State>[] = [];
Enter fullscreen mode Exit fullscreen mode

Top comments (0)