Skip to content

Releases: reduxjs/reselect

4.1.0-beta.0

21 Oct 02:27
Compare
Choose a tag to compare
4.1.0-beta.0 Pre-release
Pre-release

This beta release updates defaultMemoize with the ability to clear cache for a memoized function, and updates the TS types of createSelector to correctly infer the type of the function returned from the memoizer.

We would appreciate any feedback on the behavior of the new features and compatibility of the TS types, in preparation for a final 4.1.0 release.

npm i reselect@next

yarn add reselect@next

Changelog

defaultMemoize Cache Clearing

defaultMemoize now supports clearing the cache inside a memoized function. The memoized function returned from defaultMemoize will now have a .clearCache() method attached that will clear the cache.

When using createSelector, this can be accessed using selector.memoizedResultFunc.clearCache().

createSelector TypeScript Return Type Inference Improvements

createSelector should now fully infer the type of the memoized function returned by the memoize parameter. This means that standard use of createSelector, which already has defaultMemoize built in, will also correctly infer the existence of selector.memoizedResultFunc.clearCache().

What's Changed

New Contributors

Full Changelog: v4.1.0-alpha.2...v4.1.0-beta.0

v4.1.0-alpha.2

20 Oct 03:17
Compare
Choose a tag to compare
v4.1.0-alpha.2 Pre-release
Pre-release

This alpha release updates defaultMemoize to accept new options for cache size > 1 and a result equality check, updates createSelector to accept an options object containing options for the provided memoize function, improves some error messages, and adds memoizedResultFunc and lastResult to the fields attached to the selector.

These changes enable major improvements in functionality for createSelector, and should resolve almost all the concerns and pain points experienced by our users.

Although marked as an alpha, the code should be stable and be ready to ship as 4.1.0 in the very near future pending feedback on any potential upgrade issues.

npm i reselect@next

yarn add reselect@next

Changelog

New defaultMemoize Options

defaultMemoize has always been fairly limited. Its signature was (func: Function, equalityCheck?: EqualityFn) => Function, and only ever had a cache size of 1. This has led to many annoyances and workarounds, typically involving calling createSelectorCreator() with a custom memoization function that has a larger cache size or more options for customizing comparisons.

We've updated defaultMemoize to allow cache sizes > 1, as well as customize comparisons of the newly generated result value to improve cache hits.

The signature for defaultMemoize is now:

interface DefaultMemoizeOptions {
  equalityCheck?: EqualityFn
  resultEqualityCheck?: EqualityFn
  maxSize?: number
}

// defaultMemoize now supports a configurable cache size with LRU behavior,
// and optional comparison of the result value with existing values
export function defaultMemoize<F extends (...args: any[]) => any>(
  func: F,
  equalityCheckOrOptions?: EqualityFn | DefaultMemoizeOptions
): F 

In other words, you can still pass equalityCheck as its one additional arg, or you may pass an object containing several possible options.

If the maxSize value is greater than 1, defaultMemoize will now use an LRU cache based on https://github.com/erikras/lru-memoize internally.

If resultEqualityCheck is provided, it will be used to compare the newly-generated value from func against all other values in the cache, in LRU order. If a cached value is found to be equal, that value will be returned. This addresses the common todos.map(todo => todo.id) use case, where a change to any field in any todo object creates a new todos array and thus causes the output to be recalculated, but the generated IDs array is still shallow-equal to the last result. You can now pass an equality function like shallowEqual as the resultEqualityCheck argument, and it will reuse the old IDs array instead.

createSelector Options

Previously, the only way to customize behavior of createSelector was to generate a customized version with createSelectorCreator. By far the most common use case was customizing the equalityCheck option used with defaultMemoize, or using a different memoizer entirely. This usually looked like:

const createShallowEqualSelector = createSelectorCreator(defaultMemoize, shallowEqual)
const createDeepEqualSelector = createSelectorCreator(defaultMemoize, _.isEqual)
const createCustomComparisonSelector = createSelector(_.memoize, hashFn)

createSelectorCreator also accepted additional positional parameters, and forwarded all of them to the provided memoize function, so defaultMemoize ultimately gets called internally as defaultMemoize(actualFunction, shallowEqual).

This added an annoying level of indirection to common customization use cases.

createSelector now accepts an options object as its last argument, after the output selector. Currently, that object only includes one field: memoizeOptions:

interface CreateSelectorOptions<MemoizeOptions extends unknown[]> {
  memoizeOptions: MemoizeOptions[0] | MemoizeOptions
}

Similar to how createSelectorCreator accepts additional "options args" that get forwarded to the memoization function, the memoizeOptions field accepts an array of those "options args" as well. If provided, these override what was given to createSelectorCreator.

That means that you can now customize memoization behavior with direct options to createSelector. And, because defaultMemoize now accepts more options, you can directly customize defaultMemoize's behavior without using createSelectorCreator.

Additionally, because it's very common to only need to pass one options arg to the memoization function, memoizeOptions may also be just that first options arg by itself, without any array.

Example usages of this look like:

  const createSelectorAcceptsArgsAsArray = createSelector(
    (state: StateAB) => state.a,
    (state: StateAB) => state.b,
    (a, b) => a + b,
    {
      // Pass `equalityCheck`, the first options arg of `defaultMemoize`, in an array
      memoizeOptions: [(a, b) => a === b]
    }
  )
  
  const createSelectorFirstArgDirectly = createSelector(
    (state: StateAB) => state.a,
    (state: StateAB) => state.b,
    (a, b) => a + b,
    {
      // Pass `equalityCheck`, the first options arg of `defaultMemoize`, directly
      memoizeOptions: (a, b) => a === b
    }
  )

  const defaultMemoizeAcceptsFirstArgAsObject = createSelector(
    (state: StateAB) => state.a,
    (state: StateAB) => state.b,
    (a, b) => a + b,
    {
      // Pass `options`, the _alternate_ first arg of `defaultMemoize`, directly
      memoizeOptions: {
        equalityCheck: (a, b) => a === b,
        maxSize: 10,
        resultEqualityCheck: shallowEqual
      }
    }
  )

  // Can still create custom selectors by passing args to `createSelectorCreator`
  const customSelectorCreatorMicroMemoize = createSelectorCreator(
    microMemoize,
    {
      maxSize: 42
    }
  )

This should make it much easier to customize behavior.

All of this is fully TypeScript-typed, and the possible values for memoizeOptions should be fully inferred from the provided memoize function.

Additional Tweaks

We've improved the error messages thrown when invalid selectors are provided.

Generated selectors now include selector.memoizedResultFunc and selector.lastResult for later access if needed.

What's Changed

  • Added missing return types to a couple of functions by @nialldbarber in #512
  • Update createSelector and defaultMemoize to accept options (maxSize, equalityCheck, resultEqualityCheck) by @markerikson in #513
  • Additional 4.1 tweaks based on existing PRs by @markerikson in #514

New Contributors

Full Changelog: v4.1.0-alpha.1...v4.1.0-alpha.2

v4.1.0-alpha.1

17 Oct 22:03
Compare
Choose a tag to compare
v4.1.0-alpha.1 Pre-release
Pre-release

This alpha release migrates the Reselect source to TypeScript, and updates all associated build tooling. There are no further changes to runtime behavior.

npm i reselect@next

yarn add reselect@next

We plan on tackling actual API improvements in upcoming alpha releases, such as possible new options for cache size and memoization behavior.

Changes

TypeScript Migration

Following on from the rewrite of the TS typedefs in https://github.com/reduxjs/reselect/releases/tag/v4.1.0-alpha.0 , we've gone ahead and migrated the actual Reselect source to TS using those updated types. There were some additional tweaks needed to make this work (such as using interfaces rather than function overloads), but the types themselves should work exactly the same as alpha.0. All existing type tests pass, and we've confirmed that some existing TS+Redux apps still compile correctly if Reselect is upgraded to this build.

Along with that, the build tooling has been updated to properly compile TypeScript (based on the current build setup for React-Redux), and we've switched the test setup to use Jest instead of Mocha for consistency.

Changelog

v4.1.0-alpha.0...v4.1.0-alpha.1

v4.1.0-alpha.0

16 Oct 22:52
Compare
Choose a tag to compare
v4.1.0-alpha.0 Pre-release
Pre-release

This alpha preview release rewrites the TypeScript types to target TypeScript 4.2+, adds automatic type inference for createStructuredSelector, fixes a longstanding bug with the equalityCheck argument to defaultMemoize and its usage with createSelectorCreator, and updates build tooling.

npm i reselect@next

yarn add reselect@next

This is the first release in several years, due to the original maintainer @ellbee dealing with other obligations. Thanks to him for all his hard work, and for giving additional maintainers access.

We have an open roadmap discussion asking for feedback on a potential Reselect v5 API design, and would appreciate additional input and ideas there.

Changelog

TypeScript Target Version Updated to 4.2+

The Reselect types were written several years ago and originally targeted TS 2.x versions. As a result, the typedefs requires dozens of overloads to handle varying numbers of arguments (see the legacy typedefs file for examples).

We've completely rewritten the TS typedefs to use modern TS syntax like mapped types. This drastically shrinks the size of the typedefs (from 1000 lines to about 115), and also improves the actual type inference overall.

The updated types do require use of TS 4.2+. We've attempted to keep the final public type names and usage the same, but there may also be some types breakage. We'd appreciate feedback on any meaningful breakage issues so we can make further tweaks if needed.

Given the intent of the improvements, that they're all type-only changes, the attempts to retain backwards compatibility, and TS's own versioning scheme, we're considering this to be a minor version change rather than a major.

The legacy types are still included, and should automatically be used if you are using TS 4.1 and earlier.

Additional Type Fixes

In some cases passing an equalityCheck function to defaultMemoize would not infer the right types for the (a, b) arguments, either when used by itself or as an argument to createSelectorCreator. Those types should now be inferred correctly.

As part of that work, the types had long declared that equalityCheck functions took index: number as a third parameter. That has not been true in the actual JS code since late 2016, but the types weren't updated to match the runtime behavior. That is now fixed.

A new overload of createSelectorCreator has been added that will infer the type of state for the overall selector if all input selectors have the state argument typed.

Build Tooling Updates

Reselect now (finally) uses Babel 7. We're using Github Actions for CI and running type tests against TS4.2+.

Changes

This alpha release is from a still-draft PR, #486, and contains code from:

Full Changelog: v4.0.0...v4.1.0-alpha.0

v4.0.0

30 Sep 11:50
Compare
Choose a tag to compare

New Features

Updated TypeScript typings (#274, #315)
Exposed selector dependencies (#251)
Use provided memoize function for selectors (#297)

Bug fix

10 May 21:57
Compare
Choose a tag to compare

Fix selector type for using the right extension, see #240

v3.0.0

24 Mar 20:32
Compare
Choose a tag to compare

New Features

Performance improvements (thanks to @johnhaley81)
Updated Typescript typings (thanks to everyone who helped)

Breaking Changes

For performance reasons, a selector is now not recalculated if its input is equal by reference (===).

Example:

import { createSelector } from 'reselect';

const mySelector = createSelector(
  state => state.values.filter(val => val < 5),
  values => {
    console.log('calling..')
    return values.reduce((acc, val) => acc + val, 0)
  }
)

var createSelector = require('./dist/reselect.js').createSelector;

const mySelector = createSelector(
  state => state.values.filter(val => val < 5),
  values => {
    console.log('calling..')
    return values.reduce((acc, val) => acc + val, 0)
  }
)

var state1 = {values: [1,2,3,4,5,6,7,8,9]};
console.log(mySelector(state1));
state1.values = [3,4,5,6,7,8,9];
console.log(mySelector(state1));
var state2 = {values: [1,2,3,4,5,6,7,8,9]};
console.log(mySelector(state2));
var state3 = {values: [3,4,5,6,7]};
console.log(mySelector(state3));

Output in v2.5.4:

calling..
10
calling..
7
calling..
10
calling..
7

Output in v3.0.0:

calling..
10
10
calling..
10
calling..
7

v3.0.0-rc

15 Mar 18:37
Compare
Choose a tag to compare
v3.0.0-rc Pre-release
Pre-release

Please try this release candidate out!

npm install -S reselect@rc

If there are no problems reported, I'll release 3.0.0 proper next week.

New Features

Performance improvements (thanks to @johnhaley81)
Updated Typescript typings (thanks to everyone who helped)

v2.5.4

17 Sep 09:28
Compare
Choose a tag to compare

Bug Fixes

Improve performance of defaultMemoize when using custom equality check. (#170)

v2.5.3

04 Jul 11:33
Compare
Choose a tag to compare

Bug Fixes

Reverts a Typescript change that was a breaking change. It will be reinstated in a major release. (#145)