From d20221fde47c4306bfb0321f9517dfa9f80db09b Mon Sep 17 00:00:00 2001 From: Brandon Date: Wed, 5 Jun 2019 23:56:19 -0500 Subject: [PATCH] docs: add exported reducer function to createReducer examples Closes #1762 --- .../ngrx.io/content/guide/entity/adapter.md | 19 +++++++--- .../recipes/additional-state-properties.md | 8 +++-- .../ngrx.io/content/guide/store/reducers.md | 35 ++++++++++++++----- projects/ngrx.io/content/navigation.json | 3 +- 4 files changed, 47 insertions(+), 18 deletions(-) diff --git a/projects/ngrx.io/content/guide/entity/adapter.md b/projects/ngrx.io/content/guide/entity/adapter.md index 513e3dd531..e0fb23ac25 100644 --- a/projects/ngrx.io/content/guide/entity/adapter.md +++ b/projects/ngrx.io/content/guide/entity/adapter.md @@ -52,7 +52,7 @@ Returns the `initialState` for entity state based on the provided type. Addition Usage: -import { createReducer } from '@ngrx/store'; +import { Action, createReducer } from '@ngrx/store'; import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity'; export interface User { @@ -70,7 +70,11 @@ export const initialState: State = adapter.getInitialState({ selectedUserId: null, }); -export const reducer = createReducer(initialState); +const userReducer = createReducer(initialState); + +export function reducer(state: State | undefined: action: Action) { + return userReducer(state, action); +} ## Adapter Collection Methods @@ -122,7 +126,7 @@ export const clearUsers = createAction('[User/API] Clear Users'); -import { createReducer, on } from '@ngrx/store'; +import { Action, createReducer, on } from '@ngrx/store'; import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity'; import { User } from '../models/user.model'; import * as UserActions from '../actions/user.actions'; @@ -139,7 +143,7 @@ export const initialState: State = adapter.getInitialState({ selectedUserId: null, }); -export const reducer = createReducer( +const userReducer = createReducer( initialState, on(UserActions.addUser, (state, { user }) => { return adapter.addOne(user, state) @@ -176,7 +180,12 @@ export const reducer = createReducer( }), on(UserActions.clearUsers, state => { return adapter.removeAll({ ...state, selectedUserId: null }); - })); + }) +); + +export function reducer(state: State | undefined: action: Action) { + return userReducer(state, action); +} export const getSelectedUserId = (state: State) => state.selectedUserId; diff --git a/projects/ngrx.io/content/guide/entity/recipes/additional-state-properties.md b/projects/ngrx.io/content/guide/entity/recipes/additional-state-properties.md index dc26ed71bb..f82d291fec 100644 --- a/projects/ngrx.io/content/guide/entity/recipes/additional-state-properties.md +++ b/projects/ngrx.io/content/guide/entity/recipes/additional-state-properties.md @@ -40,7 +40,7 @@ The entity adapter is only used to update the `EntityState` properties. The addi import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity'; -import { createReducer, on } from '@ngrx/store'; +import { Action, createReducer, on } from '@ngrx/store'; import { User } from '../models/user.model'; import * as UserActions from '../actions/user.actions'; @@ -56,7 +56,8 @@ export const initialState: State = adapter.getInitialState({ selectedUserId: null, }); -export const reducer = createReducer(initialState, +export const userReducer = createReducer( + initialState, on(UserActions.selectUser, (state, { userId }) => { return { ...state, selectedUserId: userId }; }), @@ -65,4 +66,7 @@ export const reducer = createReducer(initialState, }) ); +export function reducer(state: State | undefined: action: Action) { + return userReducer(state, action); +} diff --git a/projects/ngrx.io/content/guide/store/reducers.md b/projects/ngrx.io/content/guide/store/reducers.md index 0cee17623a..fa6052bd94 100644 --- a/projects/ngrx.io/content/guide/store/reducers.md +++ b/projects/ngrx.io/content/guide/store/reducers.md @@ -36,6 +36,7 @@ a shape for the piece of state. Each reducer function is a listener of actions. The scoreboard actions defined above describe the possible transitions handled by the reducer. Import multiple sets of actions to handle additional state transitions within a reducer. +import { Action, createReducer, on } from '@ngrx/store'; import * as ScoreboardPageActions from '../actions/scoreboard-page.actions'; export interface State { @@ -64,18 +65,28 @@ The initial values for the `home` and `away` properties of the state are 0. ### Creating the reducer function -The reducer function's responsibility is to handle the state transitions in an immutable way. Define a reducer function that handles the actions for managing the state of the scoreboard. +The reducer function's responsibility is to handle the state transitions in an immutable way. Create a reducer function that handles the actions for managing the state of the scoreboard using the `createReducer` function. -export const reducer = createReducer( - initialScoreState, +const scoreboardReducer = createReducer( + initialState, on(ScoreboardPageActions.homeScore, state => ({ ...state, home: state.home + 1 })), on(ScoreboardPageActions.awayScore, state => ({ ...state, away: state.away + 1 })), on(ScoreboardPageActions.resetScore, state => ({ home: 0, away: 0 })) ); + +export function reducer(state: State | undefined: action: Action) { + return scoreboardReducer(state, action); +} -In the example above, the reducer is handling 3 actions: `[Scoreboard Page] Home Score`, `[Scoreboard Page] Away Score`, and `[Scoreboard Page] Reset`. Each action is strongly-typed. Each action handles the state transition immutably. This means that the state transitions are not modifying the original state, but are returning a new state object using the spread operator. The spread syntax copies the properties from the current state into the object, creating a new reference. This ensures that a new state is produced with each change, preserving the purity of the change. This also promotes referential integrity, guaranteeing that the old reference was discarded when a state change occurred. +
+ +**Note:** The exported `reducer` function is necessary as [function calls are not supported](https://angular.io/guide/aot-compiler#function-calls-are-not-supported) by the AOT compiler. + +
+ +In the example above, the reducer is handling 3 actions: `[Scoreboard Page] Home Score`, `[Scoreboard Page] Away Score`, and `[Scoreboard Page] Score Reset`. Each action is strongly-typed. Each action handles the state transition immutably. This means that the state transitions are not modifying the original state, but are returning a new state object using the spread operator. The spread syntax copies the properties from the current state into the object, creating a new reference. This ensures that a new state is produced with each change, preserving the purity of the change. This also promotes referential integrity, guaranteeing that the old reference was discarded when a state change occurred.
@@ -83,7 +94,13 @@ In the example above, the reducer is handling 3 actions: `[Scoreboard Page] Home
-When an action is dispatched, _all registered reducers_ receive the action. Whether they handle the action is determined by the switch statement. For this reason, each switch statement _always_ includes a default case that returns the previous state when the reducer function doesn't need to handle the action. +When an action is dispatched, _all registered reducers_ receive the action. Whether they handle the action is determined by the `on` functions that associate one or more actions with a given state change. + +
+ +**Note:** You can also write reducers using switch statements, which was the previously defined way before reducer creators were introduced in NgRx. If you are looking for examples of reducers using switch statements, visit the documentation for [versions 7.x and prior](https://v7.ngrx.io/guide/store/reducers). + +
## Registering root state @@ -92,11 +109,11 @@ The state of your application is defined as one large object. Registering reduce import { NgModule } from '@angular/core'; import { StoreModule } from '@ngrx/store'; -import { scoreboardReducer } from './reducers/scoreboard.reducer'; +import * as fromScoreboard from './reducers/scoreboard.reducer'; @NgModule({ imports: [ - StoreModule.forRoot({ game: scoreboardReducer }) + StoreModule.forRoot({ game: fromScoreboard.reducer }) ], }) export class AppModule {} @@ -134,11 +151,11 @@ Now use the `scoreboard` reducer with a feature `NgModule` named `ScoreboardModu import { NgModule } from '@angular/core'; import { StoreModule } from '@ngrx/store'; -import { scoreboardReducer } from './reducers/scoreboard.reducer'; +import * as fromScoreboard from './reducers/scoreboard.reducer'; @NgModule({ imports: [ - StoreModule.forFeature('game', scoreboardReducer) + StoreModule.forFeature('game', fromScoreboard.reducer) ], }) export class ScoreboardModule {} diff --git a/projects/ngrx.io/content/navigation.json b/projects/ngrx.io/content/navigation.json index 934f0c97ae..038f0459db 100644 --- a/projects/ngrx.io/content/navigation.json +++ b/projects/ngrx.io/content/navigation.json @@ -67,8 +67,7 @@ "SideNav": [ { "url": "docs", - "title": "Docs", - "hidden": true + "title": "Introduction" }, { "title": "@ngrx/store",