Skip to content

Commit

Permalink
Merge pull request #239 from tylerprice1/Issue237-setSizeSideEffect
Browse files Browse the repository at this point in the history
Issue #237 - Do not call onResize during setSize updater function in createNotifier
  • Loading branch information
maslianok committed Apr 9, 2023
2 parents 3a925b1 + c9eb608 commit 2c13b62
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 27 deletions.
25 changes: 19 additions & 6 deletions src/ResizeDetector.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import React, { PureComponent, isValidElement, cloneElement, createRef, ReactNode, ReactElement } from 'react';
import React, {
PureComponent,
isValidElement,
cloneElement,
createRef,
ReactNode,
ReactElement,
MutableRefObject
} from 'react';
import { findDOMNode } from 'react-dom';

import { patchResizeHandler, isFunction, isSSR, isDOMElement, createNotifier } from './utils';
Expand All @@ -13,6 +21,11 @@ class ResizeDetector<ElementT extends HTMLElement = HTMLElement> extends PureCom
observableElement;
resizeHandler;
resizeObserver;
/**
* To access the current size in the ResizeObserver without having to recreate it each time size updates.
*/
private readonly sizeRef: MutableRefObject<ReactResizeDetectorDimensions>;

constructor(props: ResizeDetectorProps<ElementT>) {
super(props);

Expand All @@ -22,6 +35,9 @@ class ResizeDetector<ElementT extends HTMLElement = HTMLElement> extends PureCom
width: undefined,
height: undefined
};
this.sizeRef = {
current: this.state
};

this.skipOnMount = skipOnMount;
this.targetRef = createRef();
Expand All @@ -41,6 +57,7 @@ class ResizeDetector<ElementT extends HTMLElement = HTMLElement> extends PureCom

componentDidUpdate(): void {
this.attachObserver();
this.sizeRef.current = this.state;
}

componentWillUnmount(): void {
Expand Down Expand Up @@ -124,11 +141,7 @@ class ResizeDetector<ElementT extends HTMLElement = HTMLElement> extends PureCom

if (!handleWidth && !handleHeight) return;

const notifyResize = createNotifier(
setStateFunc => this.setState(setStateFunc, () => onResize?.(this.state.width, this.state.height)),
handleWidth,
handleHeight
);
const notifyResize = createNotifier(onResize, this.sizeRef, this.setState.bind(this), handleWidth, handleHeight);

entries.forEach(entry => {
const { width, height } = (entry && entry.contentRect) || {};
Expand Down
22 changes: 14 additions & 8 deletions src/useResizeDetector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,13 @@ function useResizeDetector<T extends HTMLElement = any>({

// this is a callback that will be called every time the ref is changed
// we call setState inside to trigger rerender

const onRefChange: OnRefChangeType = useCallback((node: T | null) => {
setRefElement(node);
}, []);
if (node !== refElement) {
setRefElement(node);
}
}, [refElement]);

// adding `current` to make it compatible with useRef shape
onRefChange.current = refElement;

Expand All @@ -60,6 +64,12 @@ function useResizeDetector<T extends HTMLElement = any>({
};
}, []);

/**
* To access the current size in the ResizeObserver without having to recreate it each time size updates.
*/
const sizeRef = useRef(size);
sizeRef.current = size;

useEffect(() => {
if (!handleWidth && !handleHeight) return;

Expand All @@ -68,7 +78,7 @@ function useResizeDetector<T extends HTMLElement = any>({
return;
}

const notifyResize = createNotifier(setSize, handleWidth, handleHeight);
const notifyResize = createNotifier(onResize, sizeRef, setSize, handleWidth, handleHeight);

const resizeCallback: ResizeObserverCallback = (entries: ResizeObserverEntry[]) => {
if (!handleWidth && !handleHeight) return;
Expand Down Expand Up @@ -96,11 +106,7 @@ function useResizeDetector<T extends HTMLElement = any>({
resizeObserver.disconnect();
(resizeHandler.current as DebouncedFunc<ResizeObserverCallback>).cancel?.();
};
}, [refreshMode, refreshRate, refreshOptions, handleWidth, handleHeight, observerOptions, refElement]);

useEffect(() => {
onResize?.(size.width, size.height);
}, [size]);
}, [refreshMode, refreshRate, refreshOptions, handleWidth, handleHeight, observerOptions, onResize, refElement]);

return { ref: onRefChange, ...size };
}
Expand Down
31 changes: 18 additions & 13 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,27 @@ export const isDOMElement = (element: unknown): boolean =>

export const createNotifier =
(
onResize: Props['onResize'],
sizeRef: Readonly<React.MutableRefObject<ReactResizeDetectorDimensions>>,
setSize: React.Dispatch<React.SetStateAction<ReactResizeDetectorDimensions>>,
handleWidth: boolean,
handleHeight: boolean
) =>
({ width, height }: ReactResizeDetectorDimensions): void => {
setSize(prev => {
if (prev.width === width && prev.height === height) {
// skip if dimensions haven't changed
return prev;
}

if ((prev.width === width && !handleHeight) || (prev.height === height && !handleWidth)) {
// process `handleHeight/handleWidth` props
return prev;
}

return { width, height };
});
const { current: prev } = sizeRef;

if (prev.width === width && prev.height === height) {
// skip if dimensions haven't changed
return;
}

if ((prev.width === width && !handleHeight) || (prev.height === height && !handleWidth)) {
// process `handleHeight/handleWidth` props
return;
}

onResize?.(width, height);

const newSize = { width, height };
setSize(newSize);
};

0 comments on commit 2c13b62

Please sign in to comment.