Bird
Raised Fist0
Angularframework~10 mins

NgRx store concept in Angular - Step-by-Step Execution

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Concept Flow - NgRx store concept
Component dispatches Action
Action reaches Reducer
Reducer updates State
Store holds new State
Component selects State slice
Component re-renders with new data
Shows how a component sends an action, the reducer updates the state, and the component gets updated state from the store.
Execution Sample
Angular
store.dispatch({ type: 'increment' });

const newState = reducer(oldState, { type: 'increment' });

store.select('counter').subscribe(value => console.log(value));
Dispatch an increment action, reducer updates state, component subscribes to updated counter value.
Execution Table
StepAction DispatchedOld StateReducer ResultNew State in StoreComponent Output
1increment{ counter: 0 }{ counter: counter + 1 }{ counter: 1 }1
2increment{ counter: 1 }{ counter: counter + 1 }{ counter: 2 }2
3decrement{ counter: 2 }{ counter: counter - 1 }{ counter: 1 }1
4reset{ counter: 1 }{ counter: 0 }{ counter: 0 }0
💡 No more actions dispatched, store state stable.
Variable Tracker
VariableStartAfter 1After 2After 3After 4
counter01210
Key Moments - 3 Insights
Why does the component get updated after dispatching an action?
Because the store holds the new state after the reducer runs, and the component subscribes to the store's state slice, so it re-renders with the updated value (see execution_table steps 1-4).
What happens if the reducer does not handle an action type?
The reducer returns the old state unchanged, so the store state stays the same and the component output does not change (not shown in table but implied).
Why is the state immutable in NgRx?
Because the reducer returns a new state object instead of modifying the old one, ensuring predictable state changes and easier debugging (see reducer result column in execution_table).
Visual Quiz - 3 Questions
Test your understanding
Look at the execution table, what is the counter value in the store after step 2?
A2
B1
C0
D3
💡 Hint
Check the 'New State in Store' column at step 2 in the execution_table.
At which step does the counter value decrease?
AStep 1
BStep 2
CStep 3
DStep 4
💡 Hint
Look at the 'Action Dispatched' and 'New State in Store' columns to find when counter goes down.
If the 'reset' action was not handled by the reducer, what would be the counter value after step 4?
A0
B1
C2
DUndefined
💡 Hint
Refer to the key_moments about reducer behavior when action is not handled.
Concept Snapshot
NgRx Store Concept:
- Components dispatch actions to signal events.
- Reducers receive actions and return new state.
- Store holds the current state immutably.
- Components select state slices and update automatically.
- State changes flow is unidirectional and predictable.
Full Transcript
NgRx store works by components sending actions to the store. The store passes these actions to reducers, which create a new state based on the action type. The store then updates its state immutably. Components subscribe to parts of the store state and re-render when the state changes. This flow ensures a clear, predictable way to manage app data.

Practice

(1/5)
1. What is the primary purpose of the NgRx Store in an Angular application?
easy
A. To style components with CSS dynamically
B. To handle HTTP requests and responses automatically
C. To keep all application data in one central place for easy access and updates
D. To manage routing between different pages

Solution

  1. Step 1: Understand NgRx Store role

    The NgRx Store is designed to hold the application state in one place.
  2. Step 2: Compare with other options

    Options B, C, and D describe other Angular features, not the store's purpose.
  3. Final Answer:

    To keep all application data in one central place for easy access and updates -> Option C
  4. Quick Check:

    NgRx Store = Central app data storage [OK]
Hint: NgRx Store = single source of truth for app data [OK]
Common Mistakes:
  • Confusing store with routing or HTTP services
  • Thinking store manages styles or UI directly
2. Which of the following is the correct way to dispatch an action named loadItems using NgRx Store in a component?
easy
A. this.store.call(loadItems);
B. this.store.emit(loadItems);
C. store.dispatch = loadItems();
D. this.store.dispatch(loadItems());

Solution

  1. Step 1: Recall NgRx dispatch syntax

    Actions are dispatched by calling this.store.dispatch(action()).
  2. Step 2: Check other options for syntax errors

    Options A, B, and C use incorrect methods or assignment instead of dispatch call.
  3. Final Answer:

    this.store.dispatch(loadItems()); -> Option D
  4. Quick Check:

    Dispatch action = this.store.dispatch(action()) [OK]
Hint: Dispatch actions with this.store.dispatch(action()) [OK]
Common Mistakes:
  • Using emit or call instead of dispatch
  • Assigning dispatch instead of calling it
3. Given this reducer snippet:
const initialState = { count: 0 };
function counterReducer(state = initialState, action) {
  switch(action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      return state;
  }
}

What will be the state after dispatching { type: 'increment' } twice starting from initial state?
medium
A. { count: 0 }
B. { count: 2 }
C. { count: 1 }
D. { count: -2 }

Solution

  1. Step 1: Analyze reducer behavior for 'increment'

    Each 'increment' action adds 1 to the current count.
  2. Step 2: Apply two increments starting from 0

    0 + 1 = 1 after first increment, then 1 + 1 = 2 after second increment.
  3. Final Answer:

    { count: 2 } -> Option B
  4. Quick Check:

    Two increments = count 2 [OK]
Hint: Add 1 per 'increment' action to count [OK]
Common Mistakes:
  • Counting only one increment
  • Confusing decrement with increment
4. Identify the error in this NgRx reducer code:
function todoReducer(state = [], action) {
  if (action.type === 'add') {
    state.push(action.payload);
    return state;
  }
  return state;
}
medium
A. Mutating state directly instead of returning a new state
B. Missing default case in reducer
C. Incorrect action type string
D. Reducer should not return state

Solution

  1. Step 1: Check state mutation

    The reducer uses state.push(), which changes the original array directly.
  2. Step 2: Understand NgRx immutability rule

    Reducers must return new state objects without mutating the old state.
  3. Final Answer:

    Mutating state directly instead of returning a new state -> Option A
  4. Quick Check:

    Reducers must be pure and immutable [OK]
Hint: Never mutate state; always return new object/array [OK]
Common Mistakes:
  • Using push instead of spread operator
  • Ignoring immutability in reducers
5. You want to create a feature state slice for user profiles using NgRx. Which combination correctly sets up the feature state and selector?
1. Define interface UserProfileState { name: string; age: number; }
2. Create reducer userProfileReducer
3. Register feature state with key 'userProfile'
4. Select user name from store
Which code snippet correctly selects the user name?
hard
A. const selectUserProfile = createFeatureSelector<UserProfileState>('userProfile'); const selectUserName = createSelector(selectUserProfile, state => state.name);
B. const selectUserName = createSelector('userProfile', state => state.name);
C. const selectUserProfile = createSelector('userProfile'); const selectUserName = state => state.name;
D. const selectUserName = createFeatureSelector<UserProfileState>('userProfile').pipe(map(state => state.name));

Solution

  1. Step 1: Understand feature selector usage

    Use createFeatureSelector with the feature key to get the feature state.
  2. Step 2: Create selector for user name

    Use createSelector with the feature selector and a projector function to select the name.
  3. Final Answer:

    const selectUserProfile = createFeatureSelector<UserProfileState>('userProfile'); const selectUserName = createSelector(selectUserProfile, state => state.name); -> Option A
  4. Quick Check:

    Feature selector + createSelector = correct pattern [OK]
Hint: Use createFeatureSelector then createSelector for nested state [OK]
Common Mistakes:
  • Passing string directly to createSelector
  • Using pipe on selector instead of RxJS operators in component