-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhooks.ts
More file actions
115 lines (87 loc) · 2.74 KB
/
hooks.ts
File metadata and controls
115 lines (87 loc) · 2.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import {
useCallback, useEffect, useRef, useState,
type Dispatch, type RefObject, type SetStateAction
} from 'react'
export function use_rerender () {
const set_state = useState({ })[1]
return function rerender () {
set_state({ })
}
}
export function use_modal (): ModalController {
const [visible, set_visible] = useState(false)
return {
visible,
open () {
set_visible(true)
},
close () {
set_visible(false)
}
}
}
export interface ModalController {
visible: boolean
open(): void
close(): void
}
/** 类似 useState, 同时将 state 绑定到 ref 从而方便的获取其最新的值, 返回 [state, ref, set_state] */
export function use_ref_state <TState> (initial_state?: TState | (() => TState)): [
TState,
RefObject<TState>,
Dispatch<SetStateAction<TState>>
] {
let [state, _set_state] = useState(initial_state)
let ref = useRef(state)
return [state, ref, (value: TState) => { _set_state(ref.current = value) }]
}
/** 根据 html element 渲染的高度更新 height state */
export function use_height <TElement extends HTMLElement = HTMLElement> (initial_height: number): [
number, RefObject<TElement>
] {
let [height, set_height] = useState(initial_height)
let ref = useRef<TElement>(undefined)
useEffect(() => {
if (ref.current)
set_height(ref.current.clientHeight)
}, [ref.current])
return [height, ref]
}
export function use_keydown (
on_keydown: (event: KeyboardEvent) => void,
target: EventTarget = window
) {
useEffect(() => {
target.addEventListener('keydown', on_keydown)
return () => { target.removeEventListener('keydown', on_keydown) }
}, [ ])
}
export function use_before_unload (
on_before_unload: (event: BeforeUnloadEvent) => void
) {
useEffect(() => {
window.addEventListener('beforeunload', on_before_unload)
return () => { window.removeEventListener('beforeunload', on_before_unload) }
}, [ ])
}
export interface Size {
width: number
height: number
}
export function use_size <TElement extends HTMLElement = HTMLDivElement> (
ref: RefObject<TElement>
): Size | undefined {
let [size, set_size] = useState<Size | undefined>(undefined)
const on_resize = useCallback((entries: ResizeObserverEntry[]) => {
const { width, height } = entries[0].contentRect
set_size({ width, height })
}, [ ])
useEffect(() => {
let observer = new ResizeObserver(on_resize)
observer.observe(ref.current)
return () => {
observer.disconnect()
}
}, [ref, on_resize])
return size
}