diff --git a/docs/api/connect.md b/docs/api/connect.md index 2b87d6b6c..9e42fb421 100644 --- a/docs/api/connect.md +++ b/docs/api/connect.md @@ -233,7 +233,7 @@ connect(mapStateToProps, mapDispatchToProps, null, { context: MyContext })( ) ``` -#### `areStatesEqual: (next: Object, prev: Object) => boolean` +#### `areStatesEqual: (next: Object, prev: Object, nextOwnProps: Object, prevOwnProps: Object) => boolean` - default value: `strictEqual: (next, prev) => prev === next` @@ -244,7 +244,7 @@ const areStatesEqual = (next, prev) => prev.entities.todos === next.entities.todos ``` -You may wish to override `areStatesEqual` if your `mapStateToProps` function is computationally expensive and is also only concerned with a small slice of your state. The example above will effectively ignore state changes for everything but that slice of state. +You may wish to override `areStatesEqual` if your `mapStateToProps` function is computationally expensive and is also only concerned with a small slice of your state. The example above will effectively ignore state changes for everything but that slice of state. Additionally, `areStatesEqual` provides `nextOwnProps` and `prevOwnProps` to allow for more effective scoping of your state which your connected component is interested in, if needed. This would likely impact the other equality checks as well, depending on your `mapStateToProps` function. diff --git a/src/components/connect.tsx b/src/components/connect.tsx index 19116df41..963d72de9 100644 --- a/src/components/connect.tsx +++ b/src/components/connect.tsx @@ -231,7 +231,12 @@ export interface ConnectOptions< > { forwardRef?: boolean context?: typeof ReactReduxContext - areStatesEqual?: (nextState: State, prevState: State) => boolean + areStatesEqual?: ( + nextState: State, + prevState: State, + nextOwnProps: TOwnProps, + prevOwnProps: TOwnProps + ) => boolean areOwnPropsEqual?: ( nextOwnProps: TOwnProps, @@ -696,7 +701,7 @@ function connect< notifyNestedSubs, ]) - let actualChildProps: unknown + let actualChildProps: Record try { actualChildProps = useSyncExternalStore( diff --git a/src/connect/selectorFactory.ts b/src/connect/selectorFactory.ts index f0420a3f1..11620637a 100644 --- a/src/connect/selectorFactory.ts +++ b/src/connect/selectorFactory.ts @@ -1,7 +1,7 @@ import type { Dispatch, Action } from 'redux' import type { ComponentType } from 'react' import verifySubselectors from './verifySubselectors' -import type { EqualityFn } from '../types' +import type { EqualityFn, ExtendedEqualityFn } from '../types' export type SelectorFactory = ( dispatch: Dispatch>, @@ -59,7 +59,7 @@ export type MergeProps = ( ) => TMergedProps interface PureSelectorFactoryComparisonOptions { - readonly areStatesEqual: EqualityFn + readonly areStatesEqual: ExtendedEqualityFn readonly areStatePropsEqual: EqualityFn readonly areOwnPropsEqual: EqualityFn } @@ -132,7 +132,12 @@ export function pureFinalPropsSelectorFactory< function handleSubsequentCalls(nextState: State, nextOwnProps: TOwnProps) { const propsChanged = !areOwnPropsEqual(nextOwnProps, ownProps) - const stateChanged = !areStatesEqual(nextState, state) + const stateChanged = !areStatesEqual( + nextState, + state, + nextOwnProps, + ownProps + ) state = nextState ownProps = nextOwnProps diff --git a/src/types.ts b/src/types.ts index 599a568a3..fc4118642 100644 --- a/src/types.ts +++ b/src/types.ts @@ -10,6 +10,8 @@ export type FixTypeLater = any export type EqualityFn = (a: T, b: T) => boolean +export type ExtendedEqualityFn = (a: T, b: T, c: P, d: P) => boolean + export type AnyIfEmpty = keyof T extends never ? any : T export type DistributiveOmit = T extends unknown