0

I have been using NgRx for a while and trying to understand the functional language feature or design pattern being used to create selectors as described on this NgRx documentation page. Coming from a Object Oriented Programming background, seeing numerous functions instead of a simple call which takes a bunch of attributes has confused me.

What functional language feature or design pattern being used to create NgRx selectors?

wonderful world
  • 10,969
  • 20
  • 97
  • 194

1 Answers1

1

I guess the best explanation would be, that this solution is there to enforce one thing: Single source of truth.

// Selects user and provides no option to somehow modify the state from which it takes the slice
export const selectUser = (state: AppState) => state.selectedUser;
// Same here
export const selectAllBooks = (state: AppState) => state.allBooks;
 
// Even combined selectors work only with current state. 
// Yes, there is some logic inside, but provide same inputs and you'll get same results.
export const selectVisibleBooks = createSelector(
  selectUser,
  selectAllBooks,
  (selectedUser: User, allBooks: Book[]) => {
    if (selectedUser && allBooks) {
      return allBooks.filter((book: Book) => book.userId === selectedUser.id);
    } else {
      return allBooks;
    }
  }
);

If you had the possibility to provide a state to the selector, or to provide partial selectors in case of the combined ones, how would you be sure that none of them were modified prior to selecting?

Imagine a situation like this:

//current state:
{
  user: {
    id: 1,
    name: 'John Doe'
  }
  books: [
    { id: 100, userId: 1, name: 'Exiting Vim - eventually' },
    { id: 200, userId: 2, name: 'Z-index: 10000000; - Real world CSS' }
  ]
}

// Component A

// Using selector like this, you are sure, that you'll get visible books
// for current user. In a predictable manner
this.result = this.store.select(selectVisibleBooks);

// Component B

// Now imagine you had the ability to provide user;
const user = this.store.select(selectUser);
this.result = this.store.select(selectVisibleBooks(user));

// What would stop you from doing this?
const oldUser = this.store.select(selectUser);
const user = { ...oldUser, id: 3 };
this.result = this.store.select(selectVisibleBooks(user));

// Component C
// Same thing, but imagine you provided your own version of state to the selector
const oldState = this.store.select(all); // Fake, imagine you're selecting everything
const state = { ...oldState, user: { id: 4, name: 'Jane Doe' }}
this.result = this.store.select(state, selectVisibleBooks);

// The "same selector" would return different things, depending on parameters, 
// breaking the 'Predictability' principle of the Redux/NgRx

As I said, I always took it as a form of enforcing the single source of truth. This is achieved by currying the selectors, not giving you the ability to provide modified state or slice while selecting desired slice of the state.

And if you think of selectors with props - nowadays Factory Selectors, they still only allow you to send a parameter to modify the selection, but they still rely on curried functions, not allowing you to provide the state itself.

mat.hudak
  • 2,803
  • 2
  • 24
  • 39