Skip to content

Commit 3eb531a

Browse files
feat: add onChange callback to useWindowSize
1 parent e1d0cd9 commit 3eb531a

File tree

3 files changed

+57
-4
lines changed

3 files changed

+57
-4
lines changed

docs/useWindowSize.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,18 @@ const Demo = () => {
1919
);
2020
};
2121
```
22+
23+
## Reference
24+
25+
```js
26+
useWindowSize(options);
27+
```
28+
29+
- `initialWidth` — Initial width value for non-browser environments.
30+
- `initialHeight` — Initial height value for non-browser environments.
31+
- `onChange` — Callback function triggered when the window size changes.
32+
33+
## Related hooks
34+
35+
- [useSize](./useSize.md)
36+
- [useMeasure](./useMeasure.md)

src/useWindowSize.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,17 @@ import { useEffect } from 'react';
33
import useRafState from './useRafState';
44
import { isBrowser, off, on } from './misc/util';
55

6-
const useWindowSize = (initialWidth = Infinity, initialHeight = Infinity) => {
6+
interface Options {
7+
initialWidth?: number;
8+
initialHeight?: number;
9+
onChange?: (width: number, height: number) => void;
10+
}
11+
12+
const useWindowSize = ({
13+
initialWidth = Infinity,
14+
initialHeight = Infinity,
15+
onChange,
16+
}: Options = {}) => {
717
const [state, setState] = useRafState<{ width: number; height: number }>({
818
width: isBrowser ? window.innerWidth : initialWidth,
919
height: isBrowser ? window.innerHeight : initialHeight,
@@ -12,10 +22,15 @@ const useWindowSize = (initialWidth = Infinity, initialHeight = Infinity) => {
1222
useEffect((): (() => void) | void => {
1323
if (isBrowser) {
1424
const handler = () => {
25+
const width = window.innerWidth;
26+
const height = window.innerHeight;
27+
1528
setState({
1629
width: window.innerWidth,
1730
height: window.innerHeight,
1831
});
32+
33+
if (onChange) onChange(width, height);
1934
};
2035

2136
on(window, 'resize', handler);

tests/useWindowSize.test.tsx

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ describe('useWindowSize', () => {
2121
expect(useWindowSize).toBeDefined();
2222
});
2323

24-
function getHook(...args) {
25-
return renderHook(() => useWindowSize(...args));
24+
function getHook(options?: any) {
25+
return renderHook(() => useWindowSize(options));
2626
}
2727

2828
function triggerResize(dimension: 'width' | 'height', value: number) {
@@ -44,7 +44,7 @@ describe('useWindowSize', () => {
4444
});
4545

4646
it('should use passed parameters as initial values in case of non-browser use', () => {
47-
const hook = getHook(1, 1);
47+
const hook = getHook({ initialWidth: 1, initialHeight: 1 });
4848

4949
expect(hook.result.current.height).toBe(isBrowser ? window.innerHeight : 1);
5050
expect(hook.result.current.width).toBe(isBrowser ? window.innerWidth : 1);
@@ -85,4 +85,27 @@ describe('useWindowSize', () => {
8585

8686
expect(hook.result.current.width).toBe(2048);
8787
});
88+
89+
it('should call onChange callback on window resize', () => {
90+
const onChange = jest.fn();
91+
getHook({ onChange });
92+
93+
act(() => {
94+
triggerResize('width', 720);
95+
triggerResize('height', 480);
96+
requestAnimationFrame.step();
97+
});
98+
99+
expect(onChange).toHaveBeenCalledWith(720, 480);
100+
expect(onChange).toHaveBeenCalledTimes(2);
101+
102+
act(() => {
103+
triggerResize('width', 1920);
104+
triggerResize('height', 1080);
105+
requestAnimationFrame.step();
106+
});
107+
108+
expect(onChange).toHaveBeenCalledWith(1920, 1080);
109+
expect(onChange).toHaveBeenCalledTimes(4);
110+
});
88111
});

0 commit comments

Comments
 (0)