feat: add onChange callback to useWindowSize

This commit is contained in:
Mahmoud El-Gammal 2024-12-02 16:51:00 +02:00
parent e1d0cd9f7f
commit 3eb531ac9e
3 changed files with 57 additions and 4 deletions

View File

@ -19,3 +19,18 @@ const Demo = () => {
);
};
```
## Reference
```js
useWindowSize(options);
```
- `initialWidth` — Initial width value for non-browser environments.
- `initialHeight` — Initial height value for non-browser environments.
- `onChange` — Callback function triggered when the window size changes.
## Related hooks
- [useSize](./useSize.md)
- [useMeasure](./useMeasure.md)

View File

@ -3,7 +3,17 @@ import { useEffect } from 'react';
import useRafState from './useRafState';
import { isBrowser, off, on } from './misc/util';
const useWindowSize = (initialWidth = Infinity, initialHeight = Infinity) => {
interface Options {
initialWidth?: number;
initialHeight?: number;
onChange?: (width: number, height: number) => void;
}
const useWindowSize = ({
initialWidth = Infinity,
initialHeight = Infinity,
onChange,
}: Options = {}) => {
const [state, setState] = useRafState<{ width: number; height: number }>({
width: isBrowser ? window.innerWidth : initialWidth,
height: isBrowser ? window.innerHeight : initialHeight,
@ -12,10 +22,15 @@ const useWindowSize = (initialWidth = Infinity, initialHeight = Infinity) => {
useEffect((): (() => void) | void => {
if (isBrowser) {
const handler = () => {
const width = window.innerWidth;
const height = window.innerHeight;
setState({
width: window.innerWidth,
height: window.innerHeight,
});
if (onChange) onChange(width, height);
};
on(window, 'resize', handler);

View File

@ -21,8 +21,8 @@ describe('useWindowSize', () => {
expect(useWindowSize).toBeDefined();
});
function getHook(...args) {
return renderHook(() => useWindowSize(...args));
function getHook(options?: any) {
return renderHook(() => useWindowSize(options));
}
function triggerResize(dimension: 'width' | 'height', value: number) {
@ -44,7 +44,7 @@ describe('useWindowSize', () => {
});
it('should use passed parameters as initial values in case of non-browser use', () => {
const hook = getHook(1, 1);
const hook = getHook({ initialWidth: 1, initialHeight: 1 });
expect(hook.result.current.height).toBe(isBrowser ? window.innerHeight : 1);
expect(hook.result.current.width).toBe(isBrowser ? window.innerWidth : 1);
@ -85,4 +85,27 @@ describe('useWindowSize', () => {
expect(hook.result.current.width).toBe(2048);
});
it('should call onChange callback on window resize', () => {
const onChange = jest.fn();
getHook({ onChange });
act(() => {
triggerResize('width', 720);
triggerResize('height', 480);
requestAnimationFrame.step();
});
expect(onChange).toHaveBeenCalledWith(720, 480);
expect(onChange).toHaveBeenCalledTimes(2);
act(() => {
triggerResize('width', 1920);
triggerResize('height', 1080);
requestAnimationFrame.step();
});
expect(onChange).toHaveBeenCalledWith(1920, 1080);
expect(onChange).toHaveBeenCalledTimes(4);
});
});