Skip to content

Commit 35957e7

Browse files
committed
fix(ResizeWatcher): address PR review comments
- Add getTrackedElementCount as an optional method on IResizeWatcher so TS consumers can call it via the context without casting; keeping it optional preserves the freedom for alternate implementations to not expose it. - Wire dependency array on the leak test's tracked-count effect so it only re-reads when the watcher or cycle count changes, instead of on every render. - Track the cycle() setTimeout in a ref and clear it on unmount so a pending timer cannot setState on an unmounted component if the demo is swapped within 200ms.
1 parent 98b0f3d commit 35957e7

2 files changed

Lines changed: 12 additions & 3 deletions

File tree

src/utils/ResizeWatcher.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export type ResizeWatcherStop = () => void;
66
export interface IResizeWatcher {
77
watch(element: Element, callback: ResizeWatcherCallback): void;
88
unwatch(element: Element, callback: ResizeWatcherCallback): void;
9+
getTrackedElementCount?(): number;
910
}
1011

1112
export const ResizeWatcherContext = createContext<IResizeWatcher | null>(null);

usage/src/Tests/ResizeWatcherLeakTest.jsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ function ResizeWatcherStats({ cycleCount }) {
2020
const [trackedCount, setTrackedCount] = useState(0);
2121

2222
useEffect(() => {
23-
// Read count after each render triggered by a cycle.
23+
// Re-read the count whenever a cycle completes.
2424
if (resizeWatcher && typeof resizeWatcher.getTrackedElementCount === 'function') {
2525
setTrackedCount(resizeWatcher.getTrackedElementCount());
2626
}
27-
});
27+
}, [resizeWatcher, cycleCount]);
2828

2929
return (
3030
<div
@@ -83,11 +83,12 @@ function Example() {
8383
const [showViews, setShowViews] = useState(true);
8484
const [cycleCount, setCycleCount] = useState(0);
8585
const intervalRef = useRef(null);
86+
const cycleTimeoutRef = useRef(null);
8687
const [autoCycle, setAutoCycle] = useState(false);
8788

8889
const cycle = () => {
8990
setShowViews(false);
90-
setTimeout(() => {
91+
cycleTimeoutRef.current = setTimeout(() => {
9192
setShowViews(true);
9293
setCycleCount((c) => c + 1);
9394
}, 200);
@@ -102,6 +103,13 @@ function Example() {
102103
return () => clearInterval(intervalRef.current);
103104
}, [autoCycle]);
104105

106+
useEffect(
107+
() => () => {
108+
if (cycleTimeoutRef.current) clearTimeout(cycleTimeoutRef.current);
109+
},
110+
[]
111+
);
112+
105113
return (
106114
<MultiViewRoot style={{ width: '100%' }}>
107115
<div style={{ padding: '8px', display: 'flex', flexDirection: 'column', gap: '8px' }}>

0 commit comments

Comments
 (0)