Best Practices
There are a few details that will help you skip running as many functions as possible and get the best possible performance out of Reselect:
- Due to the "Cascading Memoization" in Reselect, The first layer of checks is upon the arguments that are passed to the output selector, therefore it's best to maintain the same reference for the arguments as much as possible.
- In Redux, your state will change reference when updated. But it's best to keep the additional arguments as simple as possible, you can pass in objects or array as long as their reference does not change. Or you can pass in primitives like numbers for ids.
- Keep your input selectors as simple as possible. It's best if they mostly consist of field accessors like
state => state.todos
or argument providers like(state, id) => id
. You should not be doing any sort of calculation inside input selectors, and you should definitely not be returning an object or array with a new reference each time. - The result function is only re-run as a last resort. So make sure to put any and all calculations inside your result function. That way, Reselect will only run those calculations if all other checks fail.
This:
// ✔️ This is optimal because we have less calculations in input selectors and more in the result function.
const selectorGood = createSelector(
[(state: RootState) => state.todos],
todos => someExpensiveComputation(todos)
)
Is preferable to this:
// ❌ This is not optimal!
const selectorBad = createSelector(
[(state: RootState) => someExpensiveComputation(state.todos)],
someOtherCalculation
)