/
hooks.ts
67 lines (52 loc) · 2.3 KB
/
hooks.ts
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
import React, { useEffect, useState } from "react"
import WM, { Worker, WorkInfo, isPeriodicWorker, isQueuedWorker } from "./workManager"
type HookWorkInfo<V> = WorkInfo<V> & { id: string }
const initialHookWorkInfo: HookWorkInfo<any> = {
id: undefined as any,
state: "unknown",
attemptCount: 0,
value: undefined,
}
/**
* React hook to enqueue some payload and watch to the work's state
* @param work the worker name and payload to be enqueued
*/
export function useEnqueue<P,V>(work: { worker: string, payload: P }): HookWorkInfo<V> {
const [info, setInfo] = useState<HookWorkInfo<V>>(initialHookWorkInfo)
useEffect(() => {
let unsubscriber: () => void
WM.enqueue(work).then((id) => unsubscriber = WM.addListener(id, (info: WorkInfo<V>) => setInfo({ ...info, id })))
return () => unsubscriber && unsubscriber()
})
return info
}
/**
* React hook to register a worker
* If the worker is periodic, the hook will return the work's state
* If the worker is queued, the hook will return another hook to enqueue work to this worker.
* @param worker the worker information to be registered
* @param lifecycle Use only with periodic worker, if this is setted to detached, the worker will continue alive after component unmounts.
*/
export function useWorker<P,V,T extends "periodic"|"queued">(
worker: Worker<P,V,T>,
lifecycle?: "attached"|"detached"
): T extends "periodic" ? HookWorkInfo<null> : (payload: P) => HookWorkInfo<V> {
const [periodicWorkerState, setPeriodicWorkerState] = useState<HookWorkInfo<null>>(initialHookWorkInfo)
useEffect(() => {
if(isPeriodicWorker(worker)) {
let unsubscriber: () => void
WM.setWorker(worker)
.then((id) => {
const listener = WM.addListener<null>(id, (info) => setPeriodicWorkerState({ ...info, id }))
unsubscriber = () => {
listener()
lifecycle!=="detached" && WM.cancel(id)
}
})
return () => unsubscriber && unsubscriber()
}
else WM.setWorker(worker)
})
if(isPeriodicWorker(worker)) return periodicWorkerState as any
return ((payload: P) => useEnqueue<P,V>({ worker: worker.name, payload })) as any
}