Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,10 @@ export type OutputSelectorFields<

/**
* The memoized version of {@linkcode OutputSelectorFields.resultFunc resultFunc}.
*
* This holds its own cache, separate from the one attached to the output
* selector itself. To fully reset a selector, call `clearCache` on both
* (e.g. `selector.clearCache()` and `selector.memoizedResultFunc.clearCache()`).
*/
memoizedResultFunc: Combiner<InputSelectors, Result> &
ExtractMemoizerFields<MemoizeFunction>
Expand Down Expand Up @@ -454,6 +458,11 @@ export type DefaultMemoizeFields = {
* This method is typically used to reset the state of the cache, allowing
* for the garbage collection of previously memoized results and ensuring
* that future calls to the function recompute the results.
*
* **Note:** An output selector keeps a separate cache for its arguments
* (`argsMemoize`) and for its result (`memoize`). Calling `clearCache` on the
* selector only clears the former; to fully reset it, also call
* `selector.memoizedResultFunc.clearCache()`.
*/
clearCache: () => void
resultsCount: () => number
Expand Down
20 changes: 20 additions & 0 deletions typescript_test/argsMemoize.typetest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1158,3 +1158,23 @@ function parameterLimit() {
}
)
}

function clearCacheExistsOnDefaultSelectorAndMemoizedResultFunc() {
// A selector created with default memoizers keeps two separate caches:
// `argsMemoize` on the selector and `memoize` on `memoizedResultFunc`.
// Both must expose the memoizer fields (e.g. `clearCache`). See #569.
const selectorDefault = createSelector(
(state: RootState) => state.todos,
todos => todos.map(t => t.id)
)

// Fields attached by `argsMemoize` (defaults to `weakMapMemoize`).
selectorDefault.clearCache()
expectExactType<number>(selectorDefault.resultsCount())
selectorDefault.resetResultsCount()

// Fields attached by `memoize` (defaults to `weakMapMemoize`).
selectorDefault.memoizedResultFunc.clearCache()
expectExactType<number>(selectorDefault.memoizedResultFunc.resultsCount())
selectorDefault.memoizedResultFunc.resetResultsCount()
}
20 changes: 20 additions & 0 deletions website/docs/FAQ.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,26 @@ test('selector unit test', () => {

{/* END: FAQ/howToTest.test.ts */}

:::note Resetting a selector's cache between tests

Because Reselect uses a <Link to='/introduction/how-does-reselect-work#cascading-memoization'>two-stage "cascading" memoization</Link>, a memoized selector holds _two_ separate caches:

- the `argsMemoize` cache for the arguments passed to the output selector, attached to the selector itself.
- the `memoize` cache for the results of the <InternalLinks.InputSelectors />, attached to `memoizedResultFunc`.

Calling `clearCache` on the selector only clears the first one. To fully reset a selector between tests, clear both:

```ts
selector.clearCache() // clears the `argsMemoize` cache
selector.memoizedResultFunc.clearCache() // clears the `memoize` cache
selector.resetRecomputations()
selector.resetDependencyRecomputations()
```

Alternatively, create the selector inside each test (or in a `beforeEach` block) so that every test starts with a fresh cache.

:::

## Can I share a selector across multiple component instances?

Yes, although if they pass in different arguments, you will need to handle that in order for memoization to work consistently:
Expand Down
14 changes: 14 additions & 0 deletions website/docs/api/createSelector.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'

import { InternalLinks } from '@site/src/components/InternalLinks'
import Link from '@docusaurus/Link'

# `createSelector`

Expand Down Expand Up @@ -62,6 +63,19 @@ The output selectors created by `createSelector` have several additional propert
| `memoize` | Function used to memoize the `resultFunc`. |
| `argsMemoize` | Function used to memoize the arguments passed into the <InternalLinks.OutputSelector />. |

:::note Clearing the cache

Both the output selector and its `memoizedResultFunc` expose the fields attached by their memoize function — for the built-in memoizers that means `clearCache`, `resultsCount` and `resetResultsCount`.

Because a selector keeps a <Link to='/introduction/how-does-reselect-work#cascading-memoization'>separate cache for its arguments (`argsMemoize`) and for its result (`memoize`)</Link>, fully clearing it requires calling `clearCache` on **both**:

```ts
mySelector.clearCache() // clears the `argsMemoize` cache
mySelector.memoizedResultFunc.clearCache() // clears the `memoize` cache
```

:::

## Type Parameters

| Name | Description |
Expand Down
Loading