Slide 1

Slide 1 text

NgRx Feature Creator Marko Stanimirović

Slide 2

Slide 2 text

Marko Stanimirović @MarkoStDev ★ Sr. Frontend Engineer at JobCloud ★ NgRx Team Member ★ Angular Belgrade Organizer ★ Hobby Musician ★ M.Sc. in Software Engineering

Slide 3

Slide 3 text

What is NgRx Feature?

Slide 4

Slide 4 text

Reducer

Slide 5

Slide 5 text

Reducer Feature Name

Slide 6

Slide 6 text

Reducer Feature Name Selectors

Slide 7

Slide 7 text

Reducer Feature Name Selectors NgRx Feature

Slide 8

Slide 8 text

Creating NgRx Feature

Slide 9

Slide 9 text

export interface State { songs: Song[]; activeSongId: number | null; isLoading: boolean; } const initialState: State = { songs: [], activeSongId: null, isLoading: false, }; songs.reducer.ts

Slide 10

Slide 10 text

import { createReducer } from '@ngrx/store'; export interface State { songs: Song[]; activeSongId: number | null; isLoading: boolean; } const initialState: State = { songs: [], activeSongId: null, isLoading: false, }; export const reducer = createReducer( ); songs.reducer.ts

Slide 11

Slide 11 text

import { createReducer } from '@ngrx/store'; export interface State { songs: Song[]; activeSongId: number | null; isLoading: boolean; } const initialState: State = { songs: [], activeSongId: null, isLoading: false, }; export const reducer = createReducer( initialState, ); songs.reducer.ts

Slide 12

Slide 12 text

import { createReducer, on } from '@ngrx/store'; export interface State { songs: Song[]; activeSongId: number | null; isLoading: boolean; } const initialState: State = { songs: [], activeSongId: null, isLoading: false, }; export const reducer = createReducer( initialState, on( SongsApiActions.songsLoadedSuccess, (state, { songs }) => ({ ==.state, songs, isLoading: false, }) ), on(** **. */) ); songs.reducer.ts

Slide 13

Slide 13 text

import { createReducer, on } from '@ngrx/store'; export interface State { songs: Song[]; activeSongId: number | null; isLoading: boolean; } const initialState: State = { songs: [], activeSongId: null, isLoading: false, }; export const reducer = createReducer( initialState, on( SongsApiActions.songsLoadedSuccess, (state, { songs }) => ({ ==.state, songs, isLoading: false, }) ), on(** **. */) ); export const featureName = 'songs'; songs.reducer.ts

Slide 14

Slide 14 text

songs.module.ts import { StoreModule } from '@ngrx/store'; import * as fromSongs from './songs.reducer'; @NgModule({ imports: [ StoreModule.forFeature( fromSongs.featureName, fromSongs.reducer ), ], }) export class SongsModule {} import { createReducer, on } from '@ngrx/store'; export interface State { songs: Song[]; activeSongId: number | null; isLoading: boolean; } const initialState: State = { songs: [], activeSongId: null, isLoading: false, }; export const reducer = createReducer( initialState, on( SongsApiActions.songsLoadedSuccess, (state, { songs }) => ({ ==.state, songs, isLoading: false, }) ), on(** **. */) ); export const featureName = 'songs'; songs.reducer.ts

Slide 15

Slide 15 text

import { createReducer, on } from '@ngrx/store'; export interface State { songs: Song[]; activeSongId: number | null; isLoading: boolean; } const initialState: State = { songs: [], activeSongId: null, isLoading: false, }; export const reducer = createReducer( initialState, on( SongsApiActions.songsLoadedSuccess, (state, { songs }) => ({ ==.state, songs, isLoading: false, }) ), on(** **. */) ); export const featureName = 'songs'; songs.reducer.ts songs.selectors.ts

Slide 16

Slide 16 text

import { createReducer, on } from '@ngrx/store'; export interface State { songs: Song[]; activeSongId: number | null; isLoading: boolean; } const initialState: State = { songs: [], activeSongId: null, isLoading: false, }; export const reducer = createReducer( initialState, on( SongsApiActions.songsLoadedSuccess, (state, { songs }) => ({ ==.state, songs, isLoading: false, }) ), on(** **. */) ); export const featureName = 'songs'; songs.reducer.ts import { createFeatureSelector, } from '@ngrx/store'; import * as fromSongs from './songs.reducer'; export const selectSongsState = createFeatureSelector(fromSongs.featureName); songs.selectors.ts

Slide 17

Slide 17 text

import { createReducer, on } from '@ngrx/store'; export interface State { songs: Song[]; activeSongId: number | null; isLoading: boolean; } const initialState: State = { songs: [], activeSongId: null, isLoading: false, }; export const reducer = createReducer( initialState, on( SongsApiActions.songsLoadedSuccess, (state, { songs }) => ({ ==.state, songs, isLoading: false, }) ), on(** **. */) ); export const featureName = 'songs'; songs.reducer.ts import { createFeatureSelector, createSelector, } from '@ngrx/store'; import * as fromSongs from './songs.reducer'; export const selectSongsState = createFeatureSelector(fromSongs.featureName); export const selectSongs = createSelector( selectSongsState, (state) => state.songs ); export const selectActiveSongId = createSelector( selectSongsState, (state) => state.activeSongId ); export const selectIsLoading = createSelector( selectSongsState, (state) => state.isLoading ); songs.selectors.ts

Slide 18

Slide 18 text

createFeature

Slide 19

Slide 19 text

songs.reducer.ts import { createFeature } from '@ngrx/store'; export interface State { songs: Song[]; activeSongId: number | null; isLoading: boolean; } const initialState: State = { songs: [], activeSongId: null, isLoading: false, }; export const songsFeature = createFeature({ });

Slide 20

Slide 20 text

songs.reducer.ts import { createFeature } from '@ngrx/store'; export interface State { songs: Song[]; activeSongId: number | null; isLoading: boolean; } const initialState: State = { songs: [], activeSongId: null, isLoading: false, }; export const songsFeature = createFeature({ name: 'songs' });

Slide 21

Slide 21 text

songs.reducer.ts import { createFeature, createReducer, on } from '@ngrx/store'; export interface State { songs: Song[]; activeSongId: number | null; isLoading: boolean; } const initialState: State = { songs: [], activeSongId: null, isLoading: false, }; export const songsFeature = createFeature({ name: 'songs', reducer: createReducer( initialState, on(** **. */), on(** **. */) ), });

Slide 22

Slide 22 text

songs.reducer.ts import { createFeature, createReducer, on } from '@ngrx/store'; export interface State { songs: Song[]; activeSongId: number | null; isLoading: boolean; } const initialState: State = { songs: [], activeSongId: null, isLoading: false, }; export const songsFeature = createFeature({ name: 'songs', reducer: createReducer( initialState, on(** **. */), on(** **. */) ), }); const { name, =/ feature name reducer, =/ feature reducer selectSongsState, =/ feature selector selectSongs, =/ selector for `songs` property selectActiveSongId, =/ selector for `activeSongId` property selectIsLoading, =/ selector for `isLoading` property } = songsFeature;

Slide 23

Slide 23 text

songs.reducer.ts import { createFeature, createReducer, on } from '@ngrx/store'; export interface State { songs: Song[]; activeSongId: number | null; isLoading: boolean; } const initialState: State = { songs: [], activeSongId: null, isLoading: false, }; export const songsFeature = createFeature({ name: 'songs', reducer: createReducer( initialState, on(** **. */), on(** **. */) ), }); const { name, =/ feature name reducer, =/ feature reducer selectSongsState, =/ feature selector selectSongs, =/ selector for `songs` property selectActiveSongId, =/ selector for `activeSongId` property selectIsLoading, =/ selector for `isLoading` property } = songsFeature; songs.selectors.ts import { createSelector } from '@ngrx/store'; import { songsFeature } from './songs.reducer'; export const selectActiveSong = createSelector( songsFeature.selectSongs, songsFeature.selectActiveSongId, (songs, activeSongId) => songs.find((song) => song.id === activeSongId) );

Slide 24

Slide 24 text

songs.reducer.ts import { createFeature, createReducer, on } from '@ngrx/store'; export interface State { songs: Song[]; activeSongId: number | null; isLoading: boolean; } const initialState: State = { songs: [], activeSongId: null, isLoading: false, }; export const songsFeature = createFeature({ name: 'songs', reducer: createReducer( initialState, on(** **. */), on(** **. */) ), }); const { name, =/ feature name reducer, =/ feature reducer selectSongsState, =/ feature selector selectSongs, =/ selector for `songs` property selectActiveSongId, =/ selector for `activeSongId` property selectIsLoading, =/ selector for `isLoading` property } = songsFeature; songs.module.ts import { StoreModule } from '@ngrx/store'; import { songsFeature } from './songs.reducer'; @NgModule({ imports: [ StoreModule.forFeature(songsFeature), ], }) export class SongsModule {} songs.selectors.ts import { createSelector } from '@ngrx/store'; import { songsFeature } from './songs.reducer'; export const selectActiveSong = createSelector( songsFeature.selectSongs, songsFeature.selectActiveSongId, (songs, activeSongId) => songs.find((song) => song.id === activeSongId) );

Slide 25

Slide 25 text

Marko Stanimirović @MarkoStDev Thank You!