diff --git a/docs/useWindowSize.md b/docs/useWindowSize.md index e84501cf..836d8c10 100644 --- a/docs/useWindowSize.md +++ b/docs/useWindowSize.md @@ -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) \ No newline at end of file diff --git a/src/useWindowSize.ts b/src/useWindowSize.ts index 3137307e..45f82de7 100644 --- a/src/useWindowSize.ts +++ b/src/useWindowSize.ts @@ -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); diff --git a/tests/useWindowSize.test.tsx b/tests/useWindowSize.test.tsx index dc242443..da5646f1 100644 --- a/tests/useWindowSize.test.tsx +++ b/tests/useWindowSize.test.tsx @@ -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); + }); });