Skip to content

Commit 3d345ab

Browse files
authored
ref(replays): Refactor MouseTracking component into a react hook (#36710)
Refactor the MouseTracking component into a hook which is actually more re-usable. Tested the change by making sure that the Replay Timeline still works properly, i can hover my mouse over and see the hoverTime updated in all the places on the page, and importantly the purple hoverTime bar is visible.
1 parent 15e2130 commit 3d345ab

File tree

2 files changed

+47
-35
lines changed

2 files changed

+47
-35
lines changed

static/app/components/replays/player/scrubberMouseTracking.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
import {useCallback} from 'react';
22

3-
import MouseTracking, {
4-
Props as MouseTrackingProps,
5-
} from 'sentry/components/replays/mouseTracking';
63
import {useReplayContext} from 'sentry/components/replays/replayContext';
7-
8-
type OnMouseMoveParams = Parameters<MouseTrackingProps['onMouseMove']>;
4+
import useMouseTracking from 'sentry/utils/replays/hooks/useMouseTracking';
95

106
type Props = {
117
children: React.ReactNode;
@@ -14,8 +10,8 @@ type Props = {
1410
function ScrubberMouseTracking({children}: Props) {
1511
const {duration = 0, setCurrentHoverTime} = useReplayContext();
1612

17-
const handleMouseMove = useCallback(
18-
(params: OnMouseMoveParams[0]) => {
13+
const handlePositionChange = useCallback(
14+
params => {
1915
if (!params || duration === undefined) {
2016
setCurrentHoverTime(undefined);
2117
return;
@@ -33,7 +29,11 @@ function ScrubberMouseTracking({children}: Props) {
3329
[duration, setCurrentHoverTime]
3430
);
3531

36-
return <MouseTracking onMouseMove={handleMouseMove}>{children}</MouseTracking>;
32+
const mouseTrackingProps = useMouseTracking<HTMLDivElement>({
33+
onPositionChange: handlePositionChange,
34+
});
35+
36+
return <div {...mouseTrackingProps}>{children}</div>;
3737
}
3838

3939
export default ScrubberMouseTracking;
Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
import React, {useCallback, useRef} from 'react';
1+
import {DOMAttributes, MouseEvent, useCallback, useRef} from 'react';
22
import * as Sentry from '@sentry/react';
33

44
type CallbackArgs = {height: number; left: number; top: number; width: number};
5-
export type Props = {
6-
children: React.ReactNode;
7-
onMouseMove: (args: undefined | CallbackArgs) => void;
8-
};
5+
6+
type Opts<T extends Element> = {
7+
onPositionChange: (args: undefined | CallbackArgs) => void;
8+
} & DOMAttributes<T>;
99

1010
class AbortError extends Error {}
1111

1212
/**
13-
* Replace `elem.getBoundingClientRect()` which is too laggy for onMouseMove
13+
* Replace `elem.getBoundingClientRect()` which is too laggy for onPositionChange
1414
*/
1515
function getBoundingRect(
1616
elem: Element,
@@ -38,22 +38,28 @@ function getBoundingRect(
3838
});
3939
}
4040

41-
function MouseTracking({onMouseMove, children}: Props) {
42-
const elem = useRef<HTMLDivElement>(null);
41+
function useMouseTracking<T extends Element>({
42+
onPositionChange,
43+
onMouseEnter,
44+
onMouseMove,
45+
onMouseLeave,
46+
...rest
47+
}: Opts<T>) {
48+
const elem = useRef<T>(null);
4349
const controller = useRef<AbortController>(new AbortController());
4450

45-
const handleMouseMove = useCallback(
46-
async (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
51+
const handlePositionChange = useCallback(
52+
async (e: MouseEvent<T>) => {
4753
if (!elem.current) {
48-
onMouseMove(undefined);
54+
onPositionChange(undefined);
4955
return;
5056
}
5157

5258
try {
5359
const rect = await getBoundingRect(elem.current, {
5460
signal: controller.current.signal,
5561
});
56-
onMouseMove({
62+
onPositionChange({
5763
height: rect.height,
5864
left: Math.min(e.clientX - rect.left, rect.width),
5965
top: Math.min(e.clientY - rect.top, rect.height),
@@ -68,28 +74,34 @@ function MouseTracking({onMouseMove, children}: Props) {
6874
Sentry.captureException(err);
6975
}
7076
},
71-
[onMouseMove, controller]
77+
[onPositionChange, controller]
7278
);
7379

74-
const onMouseLeave = useCallback(() => {
80+
const handleOnMouseLeave = useCallback(() => {
7581
if (controller.current) {
7682
controller.current.abort();
7783
controller.current = new AbortController();
7884
}
7985

80-
onMouseMove(undefined);
81-
}, [onMouseMove, controller]);
86+
onPositionChange(undefined);
87+
}, [onPositionChange, controller]);
8288

83-
return (
84-
<div
85-
ref={elem}
86-
onMouseEnter={handleMouseMove}
87-
onMouseMove={handleMouseMove}
88-
onMouseLeave={onMouseLeave}
89-
>
90-
{children}
91-
</div>
92-
);
89+
return {
90+
ref: elem,
91+
...rest,
92+
onMouseEnter: (e: MouseEvent<T>) => {
93+
handlePositionChange(e);
94+
onMouseEnter?.(e);
95+
},
96+
onMouseMove: (e: MouseEvent<T>) => {
97+
handlePositionChange(e);
98+
onMouseMove?.(e);
99+
},
100+
onMouseLeave: (e: MouseEvent<T>) => {
101+
handleOnMouseLeave();
102+
onMouseLeave?.(e);
103+
},
104+
};
93105
}
94106

95-
export default MouseTracking;
107+
export default useMouseTracking;

0 commit comments

Comments
 (0)