/
hooks.ts
71 lines (69 loc) · 2.18 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
68
69
70
71
import { useContext, useMemo } from 'https://esm.sh/react'
import util from '../../shared/util.ts'
import type { RouterURL } from '../../types.ts'
import events from '../core/events.ts'
import { RouterContext } from './context.ts'
import { AsyncUseDenoError } from './error.ts'
/**
* `useRouter` allows you to use `RouterURL` obeject of routing
*
* ```tsx
* export default function App() {
* const { locale, pathname, pagePath, params, query } = useRouter()
* return <p>{pathname}</p>
* }
* ```
*/
export function useRouter(): RouterURL {
return useContext(RouterContext)
}
/**
* `useDeno` allows you to use Deno runtime in build time(SSR).
*
* ```tsx
* export default function App() {
* const version = useDeno(() => Deno.version.deno)
* return <p>{version}</p>
* }
* ```
*
* @param {Function} callback - hook callback.
* @param {number} revalidate - revalidate duration in seconds.
*/
export function useDeno<T = any>(callback: () => (T | Promise<T>), revalidate?: number): T {
const id = arguments[2] // generated by compiler
const { pathname } = useRouter()
return useMemo(() => {
const global = globalThis as any
const dataUrl = 'data://' + pathname
const eventName = 'useDeno-' + dataUrl
const key = dataUrl + '#' + id
const expires = revalidate ? Date.now() + revalidate * 1000 : 0
const renderingDataCache = global['rendering-' + dataUrl]
if (renderingDataCache && key in renderingDataCache) {
return renderingDataCache[key] // 2+ pass
} else if (util.inDeno()) {
const v = callback()
if (v instanceof Promise) {
events.emit(eventName, id, v.then(value => {
if (renderingDataCache) {
renderingDataCache[key] = value
}
events.emit(eventName, id, { value, expires })
}))
// thow an `AsyncUseDenoError` to break current rendering, then re-render
throw new AsyncUseDenoError()
} else {
if (renderingDataCache) {
renderingDataCache[key] = v
}
events.emit(eventName, id, { value: v, expires })
return v
}
}
if (key in global) {
return global[key].value
}
return null
}, [id, pathname])
}