- Working with collections should be fast
- Collections are very common
@ngrx/entity
provides a common set of basic operations@ngrx/entity
provides a common set of basic state derivations
How to add @ngrx/entity
- Start by creating a
state
that extends theentityState
// From:
// export interface State {
// collection: BookModel[];
// activeBookId: string | null;
// }
// To:
export interface State extends EntityState<BookModel> {
activeBookId: string | null;
}
- Create an adapter and define the initial state with it.
Note that the collection
is no longer needed
// From:
// export const initialState: State = {
// collection: [],
// activeBookId: null
// };
// To:
const adapter = createEntityAdapter<BookModel>();
export const initialState: State = adapter.getInitialState({
activeBookId: null
});
- Out of the box, it uses the 'id' as the id, but we can also specify custom id and comparer.
const adapter = createEntityAdapter<BookModel>({
selectId: (model: BookModel) => model.name,
sortComparer:(a:BookModel,b:BookModel)=> a.name.localeCompare(b.name)
});
- Refactor the reducers to use the entity adapter
// on(BooksApiActions.bookCreated, (state, action) => {
// return {
// collection: createBook(state.collection, action.book),
// activeBookId: null
// };
// }),
on(BooksApiActions.bookCreated, (state, action) => {
return adapter.addOne(action.book, {
...state,
activeBookId: null
})
}),
// on(BooksApiActions.bookUpdated, (state, action) => {
// return {
// collection: updateBook(state.collection, action.book),
// activeBookId: null
// };
// }),
on(BooksApiActions.bookUpdated, (state, action) => {
return adapter.updateOne(
{id: action.book.id, changes: action.book},
{
...state,
activeBookId: null
})
}),
// on(BooksApiActions.bookDeleted, (state, action) => {
// return {
// ...state,
// collection: deleteBook(state.collection, action.bookId)
// };
// })
on(BooksApiActions.bookDeleted, (state, action) => {
return adapter.removeOne(action.bookId, state)
})
- Then create selectors using the entity adapter
// From:
// export const selectAll = (state: State) => state.collection;
// export const selectActiveBookId = (state: State) => state.activeBookId;
// export const selectActiveBook = createSelector(
// selectAll,
// selectActiveBookId,
// (books, activeBookId) => books.find(book => book.id === activeBookId) || null
// );
// To:
export const {selectAll, selectEntities} = adapter.getSelectors();
export const selectActiveBookId = (state: State) => state.activeBookId;
Adapter Collection Methods
The entity adapter also provides methods for operations against an entity. These methods can change one or many records at a time. Each method returns the newly modified state if changes were made and the same state if no changes were made.
addOne
: Add one entity to the collectionaddMany
: Add multiple entities to the collectionaddAll
: Replace current collection with provided collectionsetOne
: Add or Replace one entity in the collectionremoveOne
: Remove one entity from the collectionremoveMany
: Remove multiple entities from the collection, by id or by predicateremoveAll
: Clear entity collectionupdateOne
: Update one entity in the collectionupdateMany
: Update multiple entities in the collectionupsertOne
: Add or Update one entity in the collectionupsertMany
: Add or Update multiple entities in the collectionmap
: Update multiple entities in the collection by defining a map function, similar to Array.map