Skip to content

Commit 137e3f2

Browse files
committed
feat: useSize
1 parent e4228a7 commit 137e3f2

File tree

4 files changed

+123
-0
lines changed

4 files changed

+123
-0
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/**
2+
* title: 将 state 持久化在 localStorage 中
3+
* desc: 刷新页面后,可以看到输入框中的内容被从 localStorage 中恢复了。
4+
*/
5+
6+
import type { FunctionComponent } from 'react';
7+
import { useRef } from 'react';
8+
import { Space, Input } from 'antd';
9+
import 'antd/dist/antd.css';
10+
import { useSize } from '..';
11+
12+
const Component: FunctionComponent = () => {
13+
const elRef = useRef(null);
14+
const size = useSize(elRef);
15+
16+
return (
17+
<>
18+
<Space direction="vertical">
19+
<Space>
20+
<span>宽:{size.width}</span>
21+
<span>高:{size.height}</span>
22+
</Space>
23+
<Input.TextArea ref={elRef} />
24+
</Space>
25+
</>
26+
);
27+
};
28+
29+
export default Component;
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { useLayoutEffect, useState } from 'react';
2+
import type { BasicTarget } from '../utils/dom';
3+
import { getTargetElement } from '../utils/dom';
4+
5+
type Size = {
6+
width?: number;
7+
height?: number;
8+
};
9+
10+
export function useSize(target: BasicTarget) {
11+
const [size, setSize] = useState<Size>(() => {
12+
const el = (getTargetElement(target) || {}) as HTMLElement;
13+
return {
14+
width: el.clientWidth,
15+
height: el.clientHeight,
16+
};
17+
});
18+
19+
useLayoutEffect(() => {
20+
const el = getTargetElement(target);
21+
if (!el) {
22+
return;
23+
}
24+
25+
const resizeObserver = new ResizeObserver((entries) => {
26+
entries.forEach((entry) => {
27+
setSize({
28+
width: entry.target.clientWidth,
29+
height: entry.target.clientHeight,
30+
});
31+
});
32+
});
33+
resizeObserver.observe(el as Element);
34+
35+
// eslint-disable-next-line consistent-return
36+
return () => resizeObserver.disconnect();
37+
}, [target]);
38+
39+
return size;
40+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
---
2+
title: useSize
3+
nav:
4+
title: Hooks
5+
path: /hook
6+
order: 2
7+
---
8+
9+
# useSize
10+
11+
监听 dom 元素尺寸变化的 hook
12+
13+
<code src="./demo/useSize.tsx">
14+
15+
# API
16+
17+
```typescript
18+
const size = useSize(dom);
19+
```
20+
21+
# 返回值
22+
23+
| 参数 | 说明 | 类型 |
24+
| ---- | ------ | --------------------------------- |
25+
| size | 尺寸值 | {width?: number, height?: number} |

packages/react-hooks/src/utils/dom.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import type { MutableRefObject } from 'react';
2+
3+
type TargetElement = HTMLElement | Element | Document | Window;
4+
5+
export type BasicTarget<T = HTMLElement> =
6+
| T
7+
| null
8+
| (() => T | null)
9+
| MutableRefObject<T | null | undefined>;
10+
11+
export function getTargetElement(
12+
target?: BasicTarget<TargetElement>,
13+
defaultTarget?: TargetElement,
14+
): TargetElement | undefined | null {
15+
if (!target) {
16+
return defaultTarget;
17+
}
18+
19+
let targetElement: TargetElement | undefined | null;
20+
if (typeof target === 'function') {
21+
targetElement = target();
22+
} else if ('current' in target) {
23+
targetElement = target.current;
24+
} else {
25+
targetElement = target;
26+
}
27+
28+
return targetElement;
29+
}

0 commit comments

Comments
 (0)