Skip to content

Potentially misleading advice in "Balanced Selector Usage" #4783

Open
@jkillian

Description

@jkillian

What docs page needs to be fixed?

Link

  • Section: Balance Selector Usage
  • Page: Deriving Data with Selectors

What is the problem?

Quoting from the docs:

Similarly, don't make every single selector memoized!. Memoization is only needed if you are truly deriving results, and if the derived results would likely create new references every time. A selector function that does a direct lookup and return of a value should be a plain function, not memoized.

// ❌ DO NOT memoize: deriving data, but will return a consistent result
const selectItemsTotal = state => {
  return state.items.reduce((result, item) => {
    return result + item.total
  }, 0)
}
const selectAllCompleted = state => state.todos.every(todo => todo.completed)

What should be changed to fix the problem?

I'd be curious here if opinions differ, but I believe the advice above is misleading. Specifically, I think there are plenty of good times you want reselect-like memoization even if your selector returns a scalar value.

One big benefit of memoization is that the actual selector computation itself doesn't have to rerun in every component using the selector on every redux action if the inputs haven't changed.

Let's say for example you have 100 <Item /> components currently rendered on screen and 1000 items in the redux store. Each <Item /> does something like useSelector(selectItemsTotal). Without memoization, on every dispatched Redux action you'll end up with 100,000 additions taking place. With memoization, you'll have 1000 additions and 100 equality comparision for memoized selectors which will then opt-out of computation.

As a strawman, I'd potentially change the docs to something like the following:

Similarly, don't make every single selector memoized!. Memoization is only needed if you are truly deriving results or if the derived results would likely create new references every time. A selector function that does a direct lookup and return of a value should be a plain function, not memoized.

// ✅ SHOULD memoize: deriving data, so memoize to avoid pointless recomputations
const selectItemsTotal = state => {
  return state.items.reduce((result, item) => {
    return result + item.total
  }, 0)
}
const selectAllCompleted = state => state.todos.every(todo => todo.completed)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions