Skip to content

v5.0.0-rc.0

Pre-release
Pre-release
Compare
Choose a tag to compare
@markerikson markerikson released this 01 Dec 04:39
· 284 commits to master since this release

This release candidate switches createSelector to use weakMapMemoize as the default memoization method, adds a resultEqualityCheck option to weakMapMemoize, reworks the dev mode check setup and adds a dev-mode check for result functions that look like x => x, and makes some final types tweaks. This has breaking changes.

See the preview Redux Toolkit 2.0 + Redux core 5.0 Migration Guide for an overview of breaking changes in RTK 2.0 and Redux core.

npm install reselect@next

yarn add reselect@next

Changelog

createSelector Uses weakMapMemoize By Default

Reselect's createSelector originally only had one memoization function, which has always called defaultMemoize. It's always used a customizable comparison method to compare each argument. Over time, we added more functionality, particularly in v4.1.0 where defaultMemoize gained options for {memoize, maxSize, resultEqualityCheck}.

However, defaultMemoize has limitations. The biggest one is that the default cache size is 1. This makes selector instances hard to reuse in scenarios like list items, which might call selectSomeValue(state, props.id), and thus never actually memoize due to changing arguments. There are workarounds, but they're cumbersome - using createSelectorCreator to create a customized createSelector function with a different memoization implementation, creating unique selector instances per component, or setting a fixed maxSize.

For 5.0, we added a new weakMapMemoize memoization function, which takes a different approach. It uses an internal tree of cache nodes rather than a single value or a list of values. This gives weakMapMemoize an effectively infinite cache size!

We've done a fair amount of testing, and weakMapMemoize both performs faster and has more frequent cache hits than defaultMemoize.

Given that, we've made the switch so that createSelector uses weakMapMemoize by default! This should result in better performance for Redux and React apps that use Reselect.

This is hopefully a mostly non-breaking change at the code level, and an overall improvement at the behavior level.

This is a breaking change. weakMapMemoize does not have an equalityCheck option or allow customizing the comparison behavior - it's entirely based on reference comparisons, since it uses WeakMap/Map internally. It also does not have a maxSize option, but does have resultEqualityCheck.

If you need to customize the overall equality comparison behavior, import and pass defaultMemoize as the memoize and argsMemoize option!

Also, since defaultMemoize is no longer the actual "default" memoization function, we are considering a potential rename of defaultMemoize to something like lruMemoize to clarify the naming.

Dev-Mode Checks

Earlier, we added an inputStabilityCheck that checked for input selectors that accidentally return new references, with a globally exported override method.

In this release, we've added an additional dev mode check that looks for result functions that look like x => x - in other words, passing the input function result straight through. This is almost always a logic error. Either the input selectors are doing too much work, or the selector is just performing a straight lookup with no derived values and it should be a plain function instead of memoized.

Both checks are customizable on a per-selector-instance basis, and also controllable at a global level:

setGlobalDevModeChecks({
  inputStabilityCheck: 'always',
  identityFunctionCheck: 'never'
})

createSelector(
  [input1, input2],
  resultFn,
  {devModeChecks: {identityFunctionCheck: 'always'}}
)

What's Changed

Full Changelog: v5.0.0-beta.1...v5.0.0-rc.0