Skip to content

Commit

Permalink
Allow undefined callback in useResizeObserver #170
Browse files Browse the repository at this point in the history
  • Loading branch information
leroykorterink committed Nov 24, 2023
1 parent c7fe9d0 commit e6d9ccc
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 27 deletions.
68 changes: 44 additions & 24 deletions src/hooks/useResizeObserver/useResizeObserver.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/* eslint-disable react/jsx-no-literals, react-hooks/rules-of-hooks */
import type { Meta, StoryObj } from '@storybook/react';
import { type ReactElement, useRef, useState } from 'react';
import { useCallback, useRef, useState } from 'react';
import { useToggle } from '../useToggle/useToggle.js';
import { useResizeObserver } from './useResizeObserver.js';

const meta = {
Expand All @@ -10,30 +12,48 @@ export default meta;

type Story = StoryObj<typeof meta>;

function DemoComponent(): ReactElement {
const elementRef = useRef<HTMLDivElement>(null);
const [element, setElement] = useState<HTMLDivElement | null>(null);

useResizeObserver(elementRef, () => {
// eslint-disable-next-line no-console
console.log('Element from RefObject resized');
});

useResizeObserver(element, () => {
// eslint-disable-next-line no-console
console.log('Element from state resized');
});

return (
<>
<div ref={elementRef}></div>
<div ref={setElement}></div>
</>
);
}

export const Demo: Story = {
render() {
return <DemoComponent />;
const [enabled, onClick] = useToggle(true);

const elementRef = useRef<HTMLDivElement>(null);
const [elementRefWidth, setElementRefWidth] = useState(Number.NaN);

const [element, setElement] = useState<HTMLDivElement | null>(null);
const [elementWidth, setElementWidth] = useState(Number.NaN);

const onResizeElementRef = useCallback(() => {
setElementRefWidth(elementRef.current?.clientWidth ?? Number.NaN);
}, []);

const onResizeElement = useCallback(() => {
setElementWidth(element?.clientWidth ?? Number.NaN);
}, [element?.clientWidth]);

useResizeObserver(elementRef, enabled ? onResizeElementRef : undefined);
useResizeObserver(element, enabled ? onResizeElement : undefined);

return (
<>
<h4>Resize the window to update the width of the elements</h4>
<div ref={elementRef} style={{ outline: '1px solid red', marginBlock: 20 }}>
Enabled: {enabled.toString()};<br />
Width: {elementRefWidth};
</div>
<div ref={setElement} style={{ outline: '1px solid red', marginBlock: 20 }}>
Enabled: {enabled.toString()};<br />
Width: {elementWidth};
</div>
<button
type="button"
// eslint-disable-next-line react/jsx-no-bind
onClick={(): void => {
onClick();
}}
>
Toggle enabled
</button>
</>
);
},
};
12 changes: 9 additions & 3 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 @@ -10,20 +11,25 @@ import { unref, type Unreffable } from '../../utils/unref/unref.js';
*/
export function useResizeObserver(
target: Unreffable<Element | null>,
callback: ResizeObserverCallback,
callback?: ResizeObserverCallback | undefined,
): void {
const callbackRef = useRefValue(callback);

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

if (element === null) {
return;
}

const resizeObserverInstance = new ResizeObserver(callback);
const resizeObserverInstance = new ResizeObserver((entries, observer) => {
callbackRef.current?.(entries, observer);
});

resizeObserverInstance.observe(element);

return () => {
resizeObserverInstance.disconnect();
};
}, [target, callback]);
}, [target, callbackRef]);
}

0 comments on commit e6d9ccc

Please sign in to comment.