- 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
})),
- 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)
};
})
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);
}
- 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>[] = [];
Top comments (0)