Skip to content

Commit

Permalink
Memoize resize callback
Browse files Browse the repository at this point in the history
  • Loading branch information
leroykorterink committed Feb 9, 2024
1 parent 3e74eb8 commit b445309
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 8 deletions.
8 changes: 5 additions & 3 deletions src/hooks/useContentRect/useContentRect.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useRef, type RefObject } from 'react';
import { useRef, type RefObject, useCallback } from 'react';
import { useMount } from '../../lifecycle/hooks/useMount/useMount.js';
import { unref, type Unreffable } from '../../utils/unref/unref.js';
import { useResizeObserver } from '../useResizeObserver/useResizeObserver.js';
Expand All @@ -12,9 +12,11 @@ export function useContentRect(
): RefObject<DOMRectReadOnly | null> {
const contentRectRef = useRef<DOMRectReadOnly | null>(null);

useResizeObserver(target, (entries): void => {
const onResize = useCallback<ResizeObserverCallback>((entries): void => {
contentRectRef.current = entries.at(0)?.contentRect ?? null;
});
}, []);

useResizeObserver(target, onResize);

useMount(() => {
contentRectRef.current = unref(target)?.getBoundingClientRect() ?? null;
Expand Down
8 changes: 5 additions & 3 deletions src/hooks/useContentRectState/useContentRectState.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useRef, useState } from 'react';
import { useCallback, useRef, useState } from 'react';
import { useMount } from '../../index.js';
import { unref, type Unreffable } from '../../utils/unref/unref.js';
import { useResizeObserver } from '../useResizeObserver/useResizeObserver.js';
Expand All @@ -11,12 +11,14 @@ export function useContentRectState(target: Unreffable<Element | null>): DOMRect
const [contentRect, setContentRect] = useState<DOMRectReadOnly | null>(null);
const rafRef = useRef(0);

useResizeObserver(target, (entries) => {
const onResize = useCallback<ResizeObserverCallback>((entries) => {
cancelAnimationFrame(rafRef.current);
rafRef.current = requestAnimationFrame(() => {
setContentRect(entries.at(0)?.contentRect ?? null);
});
});
}, []);

useResizeObserver(target, onResize);

useMount(() => {
setContentRect(unref(target)?.getBoundingClientRect() ?? null);
Expand Down
10 changes: 8 additions & 2 deletions src/hooks/useResizeObserver/useResizeObserver.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useEffect } from 'react';
import { unref, type Unreffable } from '../../utils/unref/unref.js';
import { useRefValue } from '../useRefValue/useRefValue.js';

/**
* This hook allows you to add a ResizeObserver for an element and remove it
Expand All @@ -14,19 +15,24 @@ export function useResizeObserver(
callback?: ResizeObserverCallback | undefined,
options?: ResizeObserverOptions,
): void {
const callbackRef = useRefValue(callback);

useEffect(() => {
const element = unref(target);

if (element === null || callback === undefined) {
return;
}

const resizeObserver = new ResizeObserver(callback);
const resizeObserver = new ResizeObserver((...args) => {

Check failure on line 27 in src/hooks/useResizeObserver/useResizeObserver.ts

View workflow job for this annotation

GitHub Actions / build

The variable `args` should be named `arguments_`. A more descriptive name will do too
callbackRef.current?.(...args);
});

resizeObserver.observe(element, options);

return () => {
resizeObserver.disconnect();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [target, callback, ...Object.values(options ?? {})]);
}, [target, ...Object.values(options ?? {})]);
}

0 comments on commit b445309

Please sign in to comment.