Skip to content

Commit 22a0347

Browse files
authored
Merge pull request #5 from envato/optimise-rendering
Prevent unnecessary re-renders
2 parents 43e873d + dfb40f5 commit 22a0347

File tree

1 file changed

+61
-3
lines changed

1 file changed

+61
-3
lines changed

src/useResizeObserver.ts

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ import { Context } from './Context';
33
import { ObservedElement } from './ObservedElement';
44
import { ExtendedResizeObserverEntry } from './ExtendedResizeObserverEntry';
55

6+
const boxOptions = {
7+
BORDER_BOX: 'border-box', // https://caniuse.com/mdn-api_resizeobserverentry_borderboxsize
8+
CONTENT_BOX: 'content-box', // https://caniuse.com/mdn-api_resizeobserverentry_contentboxsize
9+
DEVICE_PIXEL_CONTENT_BOX: 'device-pixel-content-box' // https://github.com/w3c/csswg-drafts/pull/4476
10+
};
11+
612
/**
713
* See API Docs: {@linkcode https://github.com/envato/react-breakpoints/blob/master/docs/api.md#useresizeobserver|useResizeObserver}
814
*
@@ -25,8 +31,60 @@ export const useResizeObserver = (
2531

2632
const [observedEntry, setObservedEntry] = useState<ExtendedResizeObserverEntry | null>(null);
2733

28-
const handleResizeObservation = (resizeObserverEntry: ExtendedResizeObserverEntry) =>
29-
setObservedEntry(resizeObserverEntry);
34+
const handleResizeObservation = useCallback(
35+
(resizeObserverEntry: ExtendedResizeObserverEntry) => {
36+
if (!observedEntry) return setObservedEntry(resizeObserverEntry);
37+
38+
let isIdentical = true;
39+
40+
switch (options.box) {
41+
case boxOptions.BORDER_BOX:
42+
isIdentical = resizeObserverEntry.borderBoxSize.every(
43+
(boxSize, index) =>
44+
boxSize.inlineSize === observedEntry.borderBoxSize[index].inlineSize &&
45+
boxSize.blockSize === observedEntry.borderBoxSize[index].blockSize
46+
);
47+
break;
48+
49+
case boxOptions.CONTENT_BOX:
50+
isIdentical = resizeObserverEntry.contentBoxSize.every(
51+
(boxSize, index) =>
52+
boxSize.inlineSize === observedEntry.contentBoxSize[index].inlineSize &&
53+
boxSize.blockSize === observedEntry.contentBoxSize[index].blockSize
54+
);
55+
break;
56+
57+
case boxOptions.DEVICE_PIXEL_CONTENT_BOX:
58+
/* TypeScript 4.2 is missing devicePixelContentBoxSize. */
59+
if (typeof resizeObserverEntry.devicePixelContentBoxSize !== 'undefined') {
60+
isIdentical = resizeObserverEntry.devicePixelContentBoxSize.every((boxSize, index) => {
61+
if (typeof observedEntry.devicePixelContentBoxSize !== 'undefined') {
62+
return (
63+
boxSize.inlineSize === observedEntry.devicePixelContentBoxSize[index].inlineSize &&
64+
boxSize.blockSize === observedEntry.devicePixelContentBoxSize[index].blockSize
65+
);
66+
} else {
67+
throw Error('resizeObserverEntry does not contain devicePixelContentBoxSize.');
68+
}
69+
});
70+
} else {
71+
throw Error('resizeObserverEntry does not contain devicePixelContentBoxSize.');
72+
}
73+
break;
74+
75+
default:
76+
if (
77+
resizeObserverEntry.contentRect.width !== observedEntry.contentRect.width ||
78+
resizeObserverEntry.contentRect.height !== observedEntry.contentRect.height
79+
) {
80+
isIdentical = false;
81+
}
82+
}
83+
84+
if (!isIdentical) setObservedEntry(resizeObserverEntry);
85+
},
86+
[options.box, observedEntry]
87+
);
3088

3189
const ref = useRef<ObservedElement | null>(null);
3290

@@ -44,7 +102,7 @@ export const useResizeObserver = (
44102

45103
ref.current = node;
46104
},
47-
[resizeObserver, options]
105+
[resizeObserver, handleResizeObservation, options]
48106
);
49107

50108
return [setRef, observedEntry];

0 commit comments

Comments
 (0)