-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
hoc-timers.js
88 lines (74 loc) · 2.41 KB
/
hoc-timers.js
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
// @flow
import * as React from 'react'
type TimerProps = {
setTimeout: (func: () => void, timing: number) => TimeoutID,
clearTimeout: (id: TimeoutID) => void,
setInterval: (func: () => void, timing: number) => IntervalID,
clearInterval: (id: IntervalID) => void,
}
// TODO couldn't figure out a quick way to type this correctly
// type OptionalProps = {
// innerRef?: ?(?React.Component<any>) => void,
// }
// Use this to mix your props with timer props like type Props = PropsWithTimer<{foo: number}>
export type PropsWithTimer<P> = {|
...$Exact<P>,
...$Exact<TimerProps>,
|}
function getDisplayName(WrappedComponent): string {
return WrappedComponent.displayName || WrappedComponent.name || 'Component'
}
function HOCTimers<Props: TimerProps>(
WrappedComponent: React.ComponentType<Props>
): React.ComponentType<$Diff<Props, TimerProps>> {
class TimersComponent extends React.Component<$Diff<Props, TimerProps>> {
static displayName = `HOCTimers(${getDisplayName(WrappedComponent)})`
_timeoutIds: Array<TimeoutID> = []
_intervalIds: Array<IntervalID> = []
setTimeout = (f, n) => {
const id = setTimeout(f, n)
this._timeoutIds.push(id)
return id
}
clearTimeout = id => {
if ((id || id === 0) && this._timeoutIds.includes(id)) {
this._timeoutIds.splice(this._timeoutIds.indexOf(id), 1)
clearTimeout(id)
}
}
setInterval = (f, n) => {
const id = setInterval(f, n)
this._intervalIds.push(id)
return id
}
clearInterval = id => {
if ((id || id === 0) && this._intervalIds.includes(id)) {
this._intervalIds.splice(this._intervalIds.indexOf(id), 1)
clearInterval(id)
}
}
componentWillUnmount() {
this._timeoutIds.forEach(clearTimeout)
this._intervalIds.forEach(clearInterval)
}
render() {
// $FlowIssue TODO type this
const innerRef = (this.props.innerRef: any)
return (
<WrappedComponent
{...this.props}
ref={innerRef}
setTimeout={this.setTimeout}
setInterval={this.setInterval}
clearInterval={this.clearInterval}
clearTimeout={this.clearTimeout}
/>
)
}
}
// TODO forward a ref to `WrappedComponent` when react-redux is patched to
// work with React.forwardRef.
// https://github.com/reduxjs/react-redux/pull/1000
return TimersComponent
}
export default HOCTimers