Skip to content

Commit 48e3a79

Browse files
authored
Apply more granular memoization (#3815)
## Description Hooks and utils for creating event handlers and gesture relations were always relying on the entire config, while they require only a subset of its fields. This PR changes those to only work with what they actually need and updates the dependency arrays. ## Test plan Verify that created handlers are stable between renders, assuming the original callback is memoized.
1 parent e594da5 commit 48e3a79

File tree

11 files changed

+92
-37
lines changed

11 files changed

+92
-37
lines changed

packages/react-native-gesture-handler/src/v3/detectors/NativeDetector.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from 'react';
1+
import React, { useMemo } from 'react';
22
import HostGestureDetector from './HostGestureDetector';
33
import { configureRelations, ensureNativeDetectorComponent } from './utils';
44
import { isComposedGesture } from '../hooks/utils/relationUtils';
@@ -22,6 +22,10 @@ export function NativeDetector<THandlerData, TConfig>({
2222
ensureNativeDetectorComponent(NativeDetectorComponent);
2323
configureRelations(gesture);
2424

25+
const handlerTags = useMemo(() => {
26+
return isComposedGesture(gesture) ? gesture.tags : [gesture.tag];
27+
}, [gesture]);
28+
2529
return (
2630
<NativeDetectorComponent
2731
// @ts-ignore This is a type mismatch between RNGH types and RN Codegen types
@@ -50,7 +54,7 @@ export function NativeDetector<THandlerData, TConfig>({
5054
gesture.detectorCallbacks.onGestureHandlerAnimatedEvent
5155
}
5256
moduleId={globalThis._RNGH_MODULE_ID}
53-
handlerTags={isComposedGesture(gesture) ? gesture.tags : [gesture.tag]}
57+
handlerTags={handlerTags}
5458
style={nativeDetectorStyles.detector}>
5559
{children}
5660
</NativeDetectorComponent>
Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,25 @@
11
import { useMemo } from 'react';
22
import { BaseGestureConfig } from '../../../types';
3-
import { extractStateChangeHandlers } from '../../utils';
3+
import { prepareStateChangeHandlers } from '../../utils';
44
import { getStateChangeHandler } from '../stateChangeHandler';
55

66
export function useGestureStateChangeEvent<THandlerData, TConfig>(
77
handlerTag: number,
88
config: BaseGestureConfig<THandlerData, TConfig>
99
) {
1010
return useMemo(() => {
11-
const handlers = extractStateChangeHandlers(config);
11+
const handlers = prepareStateChangeHandlers({
12+
onBegin: config.onBegin,
13+
onStart: config.onStart,
14+
onEnd: config.onEnd,
15+
onFinalize: config.onFinalize,
16+
});
1217
return getStateChangeHandler(handlerTag, handlers);
13-
}, [handlerTag, config]);
18+
}, [
19+
handlerTag,
20+
config.onBegin,
21+
config.onStart,
22+
config.onEnd,
23+
config.onFinalize,
24+
]);
1425
}
Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,25 @@
11
import { useMemo } from 'react';
22
import { BaseGestureConfig } from '../../../types';
3-
import { extractTouchHandlers } from '../../utils';
3+
import { prepareTouchHandlers } from '../../utils';
44
import { getTouchEventHandler } from '../touchEventHandler';
55

66
export function useGestureTouchEvent<THandlerData, TConfig>(
77
handlerTag: number,
88
config: BaseGestureConfig<THandlerData, TConfig>
99
) {
1010
return useMemo(() => {
11-
const handlers = extractTouchHandlers(config);
11+
const handlers = prepareTouchHandlers({
12+
onTouchesDown: config.onTouchesDown,
13+
onTouchesMove: config.onTouchesMove,
14+
onTouchesUp: config.onTouchesUp,
15+
onTouchesCancel: config.onTouchesCancel,
16+
});
1217
return getTouchEventHandler(handlerTag, handlers);
13-
}, [handlerTag, config]);
18+
}, [
19+
handlerTag,
20+
config.onTouchesDown,
21+
config.onTouchesMove,
22+
config.onTouchesUp,
23+
config.onTouchesCancel,
24+
]);
1425
}

packages/react-native-gesture-handler/src/v3/hooks/callbacks/js/useGestureUpdateEvent.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { extractUpdateHandlers, isAnimatedEvent } from '../../utils';
1+
import { prepareUpdateHandlers, isAnimatedEvent } from '../../utils';
22
import { ReanimatedContext } from '../../../../handlers/gestures/reanimatedWrapper';
33
import { getUpdateHandler } from '../updateHandler';
44
import { BaseGestureConfig } from '../../../types';
@@ -9,7 +9,12 @@ export function useGestureUpdateEvent<THandlerData, TConfig>(
99
config: BaseGestureConfig<THandlerData, TConfig>
1010
) {
1111
return useMemo(() => {
12-
const { handlers, changeEventCalculator } = extractUpdateHandlers(config);
12+
const { handlers, changeEventCalculator } = prepareUpdateHandlers(
13+
{
14+
onUpdate: config.onUpdate,
15+
},
16+
config.changeEventCalculator
17+
);
1318

1419
const jsContext: ReanimatedContext<THandlerData> = {
1520
lastUpdateEvent: undefined,
@@ -23,5 +28,5 @@ export function useGestureUpdateEvent<THandlerData, TConfig>(
2328
jsContext,
2429
changeEventCalculator
2530
);
26-
}, [handlerTag, config]);
31+
}, [handlerTag, config.onUpdate, config.changeEventCalculator]);
2732
}

packages/react-native-gesture-handler/src/v3/hooks/callbacks/reanimated/useReanimatedStateChangeEvent.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
import { Reanimated } from '../../../../handlers/gestures/reanimatedWrapper';
22
import { BaseGestureConfig } from '../../../types';
3-
import { extractStateChangeHandlers } from '../../utils';
3+
import { prepareStateChangeHandlers } from '../../utils';
44
import { getStateChangeHandler } from '../stateChangeHandler';
55

66
export function useReanimatedStateChangeEvent<THandlerData, TConfig>(
77
handlerTag: number,
88
config: BaseGestureConfig<THandlerData, TConfig>
99
) {
10-
const handlers = extractStateChangeHandlers(config);
10+
const handlers = prepareStateChangeHandlers({
11+
onBegin: config.onBegin,
12+
onStart: config.onStart,
13+
onEnd: config.onEnd,
14+
onFinalize: config.onFinalize,
15+
});
1116

1217
const callback = getStateChangeHandler(handlerTag, handlers);
1318

packages/react-native-gesture-handler/src/v3/hooks/callbacks/reanimated/useReanimatedTouchEvent.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
import { Reanimated } from '../../../../handlers/gestures/reanimatedWrapper';
22
import { BaseGestureConfig } from '../../../types';
3-
import { extractTouchHandlers } from '../../utils';
3+
import { prepareTouchHandlers } from '../../utils';
44
import { getTouchEventHandler } from '../touchEventHandler';
55

66
export function useReanimatedTouchEvent<THandlerData, TConfig>(
77
handlerTag: number,
88
config: BaseGestureConfig<THandlerData, TConfig>
99
) {
10-
const handlers = extractTouchHandlers(config);
10+
const handlers = prepareTouchHandlers({
11+
onTouchesDown: config.onTouchesDown,
12+
onTouchesMove: config.onTouchesMove,
13+
onTouchesUp: config.onTouchesUp,
14+
onTouchesCancel: config.onTouchesCancel,
15+
});
1116

1217
const callback = getTouchEventHandler(handlerTag, handlers);
1318

packages/react-native-gesture-handler/src/v3/hooks/callbacks/reanimated/useReanimatedUpdateEvent.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
import { Reanimated } from '../../../../handlers/gestures/reanimatedWrapper';
22
import { BaseGestureConfig } from '../../../types';
3-
import { extractUpdateHandlers } from '../../utils';
3+
import { prepareUpdateHandlers } from '../../utils';
44
import { getUpdateHandler } from '../updateHandler';
55

66
export function useReanimatedUpdateEvent<THandlerData, TConfig>(
77
handlerTag: number,
88
config: BaseGestureConfig<THandlerData, TConfig>
99
) {
10-
const { handlers, changeEventCalculator } = extractUpdateHandlers(config);
10+
const { handlers, changeEventCalculator } = prepareUpdateHandlers(
11+
{
12+
onUpdate: config.onUpdate,
13+
},
14+
config.changeEventCalculator
15+
);
1116

1217
// We don't want to call hooks conditionally, therefore `useHandler` and `useEvent` will be always called.
1318
// The only difference is whether we will send events to Reanimated or not.

packages/react-native-gesture-handler/src/v3/hooks/useGesture.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,16 @@ export function useGesture<THandlerData, TConfig>(
7070
}
7171

7272
const gestureRelations = useMemo(
73-
() => prepareRelations(config, tag),
74-
[config, tag]
73+
() =>
74+
prepareRelations(
75+
{
76+
simultaneousWith: config.simultaneousWith,
77+
requireToFail: config.requireToFail,
78+
block: config.block,
79+
},
80+
tag
81+
),
82+
[tag, config.simultaneousWith, config.requireToFail, config.block]
7583
);
7684

7785
const currentGestureRef = useRef({ type: '', tag: -1 });

packages/react-native-gesture-handler/src/v3/hooks/utils/eventHandlersUtils.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
import { TouchEventType } from '../../../TouchEventType';
22
import { CALLBACK_TYPE } from '../../../handlers/gestures/gesture';
33
import {
4-
BaseGestureConfig,
54
ChangeCalculatorType,
65
UnpackedGestureHandlerEvent,
76
GestureCallbacks,
87
} from '../../types';
98

10-
export function extractStateChangeHandlers<THandlerData, TConfig>(
11-
config: BaseGestureConfig<THandlerData, TConfig>
9+
export function prepareStateChangeHandlers<THandlerData>(
10+
callbacks: GestureCallbacks<THandlerData>
1211
): GestureCallbacks<THandlerData> {
1312
'worklet';
14-
const { onBegin, onStart, onEnd, onFinalize } = config;
13+
const { onBegin, onStart, onEnd, onFinalize } = callbacks;
1514

1615
const handlers: GestureCallbacks<THandlerData> = {
1716
...(onBegin ? { onBegin } : {}),
@@ -28,11 +27,12 @@ type UpdateHandlersReturnType<THandlerData> = {
2827
changeEventCalculator?: ChangeCalculatorType<THandlerData>;
2928
};
3029

31-
export function extractUpdateHandlers<THandlerData, TConfig>(
32-
config: BaseGestureConfig<THandlerData, TConfig>
30+
export function prepareUpdateHandlers<THandlerData>(
31+
callbacks: GestureCallbacks<THandlerData>,
32+
changeEventCalculator?: ChangeCalculatorType<THandlerData>
3333
): UpdateHandlersReturnType<THandlerData> {
3434
'worklet';
35-
const { onUpdate, changeEventCalculator } = config;
35+
const { onUpdate } = callbacks;
3636

3737
const handlers: GestureCallbacks<THandlerData> = {
3838
...(onUpdate ? { onUpdate } : {}),
@@ -41,10 +41,11 @@ export function extractUpdateHandlers<THandlerData, TConfig>(
4141
return { handlers, changeEventCalculator };
4242
}
4343

44-
export function extractTouchHandlers<THandlerData, TConfig>(
45-
config: BaseGestureConfig<THandlerData, TConfig>
44+
export function prepareTouchHandlers<THandlerData>(
45+
callbacks: GestureCallbacks<THandlerData>
4646
): GestureCallbacks<THandlerData> {
47-
const { onTouchesDown, onTouchesMove, onTouchesUp, onTouchesCancel } = config;
47+
const { onTouchesDown, onTouchesMove, onTouchesUp, onTouchesCancel } =
48+
callbacks;
4849

4950
const handlers: GestureCallbacks<THandlerData> = {
5051
...(onTouchesDown ? { onTouchesDown } : {}),

packages/react-native-gesture-handler/src/v3/hooks/utils/relationUtils.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {
2-
BaseGestureConfig,
32
ComposedGesture,
3+
ExternalRelations,
44
Gesture,
55
GestureRelations,
66
} from '../../types';
@@ -58,16 +58,16 @@ function makeSimultaneousWithSymmetric(
5858
}
5959
}
6060

61-
export function prepareRelations<THandlerData, TConfig>(
62-
config: BaseGestureConfig<THandlerData, TConfig>,
61+
export function prepareRelations(
62+
relations: ExternalRelations,
6363
handlerTag: number
6464
): GestureRelations {
65-
makeSimultaneousWithSymmetric(config.simultaneousWith, handlerTag);
65+
makeSimultaneousWithSymmetric(relations.simultaneousWith, handlerTag);
6666

6767
return {
68-
simultaneousHandlers: extractHandlerTags(config.simultaneousWith),
69-
waitFor: extractHandlerTags(config.requireToFail),
70-
blocksHandlers: extractHandlerTags(config.block),
68+
simultaneousHandlers: extractHandlerTags(relations.simultaneousWith),
69+
waitFor: extractHandlerTags(relations.requireToFail),
70+
blocksHandlers: extractHandlerTags(relations.block),
7171
};
7272
}
7373

0 commit comments

Comments
 (0)