-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathindex.tsx
92 lines (85 loc) · 2.21 KB
/
index.tsx
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
/**
* @file index.ts
* @author 余聪
*
*/
import * as React from 'react'
import usePersistFn from '@rcp/use.persistfn'
const delay = (ms) => new Promise((res) => setTimeout(res, ms))
export interface UsePreventFastOperationOptions<T extends Function = () => void> {
defaultLoading?: boolean
onOperation?: T
}
export function usePreventFastOperation<T extends Function>({
onOperation,
defaultLoading
}: UsePreventFastOperationOptions<T>): [T, { loading: boolean }] {
const canClickRef = React.useRef(true)
const [loadingState, setLoading] = React.useState(defaultLoading)
// @ts-ignore
const _fn = usePersistFn(onOperation)
const fn = React.useCallback(
async (evt) => {
if (!canClickRef.current) {
return
}
if (_fn) {
canClickRef.current = false
const res = await Promise.race([
Promise.resolve(_fn(evt))
.then(() =>
// 防止同步 onClick
delay(100)
)
.finally(() => {
setLoading(false)
canClickRef.current = true
}),
new Promise((resolve) => {
setTimeout(resolve, 300, '$timeout')
})
])
if (res === '$timeout') {
setLoading(true)
canClickRef.current = false
}
}
},
[_fn, setLoading]
)
const data = React.useMemo(() => ({ loading: loadingState }), [loadingState])
return [fn as any, data]
}
export type PreventFastOperationProps = {
operationName: string
onOperation: any
defaultLoading?: boolean
children: React.ReactElement
}
export function PreventFastOperation({
operationName,
onOperation,
defaultLoading,
children,
...props
}: PreventFastOperationProps) {
const [onFn, { loading }] = usePreventFastOperation({ onOperation, defaultLoading })
return React.cloneElement(children, {
loading,
[operationName]: onFn,
...props
})
}
export function PreventFastClick({
onClick,
children,
...props
}: {
onClick?: any
} & Omit<PreventFastOperationProps, 'operationName' | 'onOperation'>) {
return (
<PreventFastOperation {...props} operationName={'onClick'} onOperation={onClick}>
{children}
</PreventFastOperation>
)
}