Skip to content

Commit

Permalink
per-hook affected
Browse files Browse the repository at this point in the history
  • Loading branch information
dai-shi committed Mar 2, 2024
1 parent 6d12a53 commit 72ea1dc
Showing 1 changed file with 9 additions and 15 deletions.
24 changes: 9 additions & 15 deletions src/createTrackedSelector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,38 +9,35 @@ import { createProxy, isChanged } from 'proxy-compare';

import { useAffectedDebugValue } from './utils';

type Affected = WeakMap<object, unknown>;

export const createTrackedSelector = <State>(
useSelector: <Selected>(selector: (state: State) => Selected) => Selected,
) => {
const useTrackedSelector = () => {
const [, forceUpdate] = useReducer((c) => c + 1, 0);
const lastStateAndAffected = useRef<readonly [State, Affected]>();
// per-hook affected, it's not ideal but memo compatible
const affected = useMemo(() => new WeakMap(), []);
const prevState = useRef<State>();
const latestState = useRef<State>();
const lastState = useRef<State>();
useEffect(() => {
lastStateAndAffected.current = [state, affected];
if (prevState.current !== latestState.current
if (prevState.current !== lastState.current
&& isChanged(
prevState.current,
latestState.current,
lastState.current,
affected,
new WeakMap(),
)) {
prevState.current = latestState.current;
prevState.current = lastState.current;
forceUpdate();
}
});
const selector = useCallback((nextState: State) => {
latestState.current = nextState;
lastState.current = nextState;
if (prevState.current
&& prevState.current !== nextState
&& lastStateAndAffected.current
&& !isChanged(
prevState.current,
nextState,
lastStateAndAffected.current[1],
affected,
new WeakMap(),
)
) {
Expand All @@ -49,11 +46,8 @@ export const createTrackedSelector = <State>(
}
prevState.current = nextState;
return nextState;
}, []);
}, [affected]);
const state = useSelector(selector);
const affected = lastStateAndAffected.current?.[0] === state
? lastStateAndAffected.current[1]
: new WeakMap();
if (typeof process === 'object' && process.env.NODE_ENV !== 'production') {
// eslint-disable-next-line react-hooks/rules-of-hooks
useAffectedDebugValue(state, affected);
Expand Down

0 comments on commit 72ea1dc

Please sign in to comment.