Bird
Raised Fist0
Angularframework~8 mins

Selectors for derived state in Angular - Performance & Optimization

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
Performance: Selectors for derived state
MEDIUM IMPACT
This affects how quickly the UI updates when state changes and how much CPU is used during rendering.
Calculating derived state from a global store to update UI
Angular
const selectActiveCount = createSelector(
  (state) => state.items,
  (items) => items.filter(item => item.active).length
);
const derivedValue = store.select(selectActiveCount);
Memoizes the filtered count, recalculating only when items change, reducing unnecessary work.
📈 Performance Gainreduces recalculations and re-renders, improving input responsiveness (INP)
Calculating derived state from a global store to update UI
Angular
const derivedValue = store.select(state => {
  return state.items.filter(item => item.active).length;
});
This recalculates the filtered list on every state change, even if unrelated parts of the state update.
📉 Performance Costtriggers multiple recalculations and re-renders, increasing CPU usage and slowing interaction
Performance Comparison
PatternDOM OperationsReflowsPaint CostVerdict
Non-memoized selectorMany recalculationsMultiple reflows due to frequent updatesHigh paint cost from unnecessary renders[X] Bad
Memoized selector with createSelectorMinimal recalculationsSingle reflow per relevant state changeLower paint cost from fewer renders[OK] Good
Rendering Pipeline
Selectors compute derived data before Angular runs change detection. Efficient selectors reduce the work Angular must do during the Layout and Paint stages.
Style Calculation
Layout
Paint
Composite
⚠️ BottleneckLayout and Paint stages due to unnecessary re-renders triggered by non-memoized selectors
Core Web Vital Affected
INP
This affects how quickly the UI updates when state changes and how much CPU is used during rendering.
Optimization Tips
1Always memoize selectors to avoid unnecessary recalculations.
2Use createSelector from Angular's store to build efficient selectors.
3Avoid inline selector functions inside components to prevent repeated work.
Performance Quiz - 3 Questions
Test your performance knowledge
What is the main performance benefit of using memoized selectors in Angular?
AThey prevent unnecessary recalculations and reduce component re-renders.
BThey increase the size of the JavaScript bundle.
CThey delay the initial page load.
DThey automatically cache HTTP requests.
DevTools: Performance
How to check: Record a performance profile while interacting with the app. Look for frequent recalculations or component re-renders in the flame chart.
What to look for: High CPU usage spikes or repeated re-rendering of components indicate inefficient selectors.

Practice

(1/5)
1. What is the main purpose of using createSelector in Angular state management?
easy
A. To dispatch actions to the store
B. To directly modify the state values
C. To compute derived data from the state efficiently
D. To subscribe to HTTP requests

Solution

  1. Step 1: Understand what createSelector does

    createSelector is used to create selectors that compute derived data from the state without modifying it.
  2. Step 2: Differentiate from other store operations

    Modifying state or dispatching actions are done by reducers and actions, not selectors.
  3. Final Answer:

    To compute derived data from the state efficiently -> Option C
  4. Quick Check:

    Derived data = createSelector [OK]
Hint: Remember: selectors read and compute, not modify state [OK]
Common Mistakes:
  • Confusing selectors with actions or reducers
  • Thinking selectors modify state
  • Assuming selectors handle side effects
2. Which of the following is the correct syntax to create a selector that derives the total count from a list in the state using createSelector?
easy
A. const selectTotal = createSelector(list => list.length, selectList);
B. const selectTotal = createSelector(selectList, list => list.length);
C. const selectTotal = createSelector(selectList, list => list.count);
D. const selectTotal = createSelector(selectList, list => list.size());

Solution

  1. Step 1: Check the order of arguments in createSelector

    The first argument(s) are input selectors, followed by a projector function.
  2. Step 2: Verify the projector function logic

    The projector function receives the selected data and returns the derived value. Using list.length correctly gets the count.
  3. Final Answer:

    const selectTotal = createSelector(selectList, list => list.length); -> Option B
  4. Quick Check:

    Input selectors first, then projector function [OK]
Hint: Input selectors first, projector function last in createSelector [OK]
Common Mistakes:
  • Swapping input selectors and projector function order
  • Using incorrect property like count or size()
  • Calling methods instead of accessing properties
3. Given the following selectors:
const selectItems = (state) => state.items;
const selectCompletedItems = createSelector(selectItems, items => items.filter(item => item.done));

What will selectCompletedItems return if state.items is [{done: true}, {done: false}, {done: true}]?
medium
A. [{done: true}, {done: true}]
B. []
C. [{done: false}]
D. [{done: true}, {done: false}]

Solution

  1. Step 1: Understand the input selector

    selectItems returns the full list of items from state.
  2. Step 2: Apply the projector function filter

    The projector filters items where item.done is true, so it keeps only those objects.
  3. Final Answer:

    [{done: true}, {done: true}] -> Option A
  4. Quick Check:

    Filter done=true items = [{done:true}, {done:true}] [OK]
Hint: Filter returns only items matching condition [OK]
Common Mistakes:
  • Including false done items in result
  • Returning original list without filtering
  • Confusing filter condition logic
4. Identify the error in this selector code:
const selectUsers = (state) => state.users;
const selectActiveUsers = createSelector(selectUsers, users => users.active);
medium
A. The projector function incorrectly accesses users.active instead of filtering
B. The input selector should return a property, not the whole state
C. createSelector requires at least two input selectors
D. The selector should be an async function

Solution

  1. Step 1: Check the input selector

    selectUsers correctly returns state.users, which is valid.
  2. Step 2: Analyze the projector function

    The projector accesses users.active, but users is likely an array, so it should filter or map, not access a property.
  3. Final Answer:

    The projector function incorrectly accesses users.active instead of filtering -> Option A
  4. Quick Check:

    Projector must handle data type correctly [OK]
Hint: Check if projector matches data type (array vs object) [OK]
Common Mistakes:
  • Assuming users is an object, not an array
  • Trying to access properties on arrays directly
  • Misunderstanding projector function role
5. You want to create a selector that returns the number of completed tasks and the number of pending tasks from state.
Given:
const selectTasks = (state) => state.tasks;

Which of the following createSelector implementations correctly derives this data?
hard
A. const selectTaskCounts = createSelector(selectTasks, tasks => tasks.doneCount)
B. const selectTaskCounts = createSelector(selectTasks, tasks => { completed: tasks.filter(t => t.done).length, pending: tasks.filter(t => !t.done).length });
C. const selectTaskCounts = createSelector(selectTasks, tasks => [tasks.filter(t => t.done).length, tasks.filter(t => !t.done).length]);
D. const selectTaskCounts = createSelector(selectTasks, tasks => ({ completed: tasks.filter(t => t.done).length, pending: tasks.filter(t => !t.done).length }));

Solution

  1. Step 1: Check the syntax of the projector function

    const selectTaskCounts = createSelector(selectTasks, tasks => ({ completed: tasks.filter(t => t.done).length, pending: tasks.filter(t => !t.done).length })); returns an object with properties completed and pending correctly using parentheses to return the object literal.
  2. Step 2: Identify errors in other options

    const selectTaskCounts = createSelector(selectTasks, tasks => { completed: tasks.filter(t => t.done).length, pending: tasks.filter(t => !t.done).length }); lacks parentheses around the object, causing a syntax error. const selectTaskCounts = createSelector(selectTasks, tasks => [tasks.filter(t => t.done).length, tasks.filter(t => !t.done).length]); returns an array, not an object. const selectTaskCounts = createSelector(selectTasks, tasks => tasks.doneCount) accesses a non-existent property.
  3. Final Answer:

    const selectTaskCounts = createSelector(selectTasks, tasks => ({ completed: tasks.filter(t => t.done).length, pending: tasks.filter(t => !t.done).length })); -> Option D
  4. Quick Check:

    Use parentheses to return object literals in arrow functions [OK]
Hint: Wrap object in parentheses to return from arrow function [OK]
Common Mistakes:
  • Missing parentheses around object literal
  • Returning array instead of object
  • Accessing undefined properties