[d24f17c] | 1 | import type { CreateSelectorOptions, UnknownMemoizer } from '../types'
|
---|
| 2 |
|
---|
| 3 | /**
|
---|
| 4 | * Runs a stability check to ensure the input selector results remain stable
|
---|
| 5 | * when provided with the same arguments. This function is designed to detect
|
---|
| 6 | * changes in the output of input selectors, which can impact the performance of memoized selectors.
|
---|
| 7 | *
|
---|
| 8 | * @param inputSelectorResultsObject - An object containing two arrays: `inputSelectorResults` and `inputSelectorResultsCopy`, representing the results of input selectors.
|
---|
| 9 | * @param options - Options object consisting of a `memoize` function and a `memoizeOptions` object.
|
---|
| 10 | * @param inputSelectorArgs - List of arguments being passed to the input selectors.
|
---|
| 11 | *
|
---|
| 12 | * @see {@link https://reselect.js.org/api/development-only-stability-checks/#inputstabilitycheck `inputStabilityCheck`}
|
---|
| 13 | *
|
---|
| 14 | * @since 5.0.0
|
---|
| 15 | * @internal
|
---|
| 16 | */
|
---|
| 17 | export const runInputStabilityCheck = (
|
---|
| 18 | inputSelectorResultsObject: {
|
---|
| 19 | inputSelectorResults: unknown[]
|
---|
| 20 | inputSelectorResultsCopy: unknown[]
|
---|
| 21 | },
|
---|
| 22 | options: Required<
|
---|
| 23 | Pick<
|
---|
| 24 | CreateSelectorOptions<UnknownMemoizer, UnknownMemoizer>,
|
---|
| 25 | 'memoize' | 'memoizeOptions'
|
---|
| 26 | >
|
---|
| 27 | >,
|
---|
| 28 | inputSelectorArgs: unknown[] | IArguments
|
---|
| 29 | ) => {
|
---|
| 30 | const { memoize, memoizeOptions } = options
|
---|
| 31 | const { inputSelectorResults, inputSelectorResultsCopy } =
|
---|
| 32 | inputSelectorResultsObject
|
---|
| 33 | const createAnEmptyObject = memoize(() => ({}), ...memoizeOptions)
|
---|
| 34 | // if the memoize method thinks the parameters are equal, these *should* be the same reference
|
---|
| 35 | const areInputSelectorResultsEqual =
|
---|
| 36 | createAnEmptyObject.apply(null, inputSelectorResults) ===
|
---|
| 37 | createAnEmptyObject.apply(null, inputSelectorResultsCopy)
|
---|
| 38 | if (!areInputSelectorResultsEqual) {
|
---|
| 39 | let stack: string | undefined = undefined
|
---|
| 40 | try {
|
---|
| 41 | throw new Error()
|
---|
| 42 | } catch (e) {
|
---|
| 43 | // eslint-disable-next-line @typescript-eslint/no-extra-semi, no-extra-semi
|
---|
| 44 | ;({ stack } = e as Error)
|
---|
| 45 | }
|
---|
| 46 | console.warn(
|
---|
| 47 | 'An input selector returned a different result when passed same arguments.' +
|
---|
| 48 | '\nThis means your output selector will likely run more frequently than intended.' +
|
---|
| 49 | '\nAvoid returning a new reference inside your input selector, e.g.' +
|
---|
| 50 | '\n`createSelector([state => state.todos.map(todo => todo.id)], todoIds => todoIds.length)`',
|
---|
| 51 | {
|
---|
| 52 | arguments: inputSelectorArgs,
|
---|
| 53 | firstInputs: inputSelectorResults,
|
---|
| 54 | secondInputs: inputSelectorResultsCopy,
|
---|
| 55 | stack
|
---|
| 56 | }
|
---|
| 57 | )
|
---|
| 58 | }
|
---|
| 59 | }
|
---|