-
Notifications
You must be signed in to change notification settings - Fork 169
/
hooks.ts
78 lines (73 loc) · 2.67 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
72
73
74
75
76
77
78
import React, { useContext, useEffect, useState } from 'https://esm.sh/react'
import { RouterContext } from './context.ts'
import { AsyncUseDenoError } from './error.ts'
import events from './events.ts'
import type { RouterURL } from './types.ts'
export function useRouter(): RouterURL {
return useContext(RouterContext)
}
export function useDeno<T = any>(callback: () => (T | Promise<T>), browser?: boolean, deps?: ReadonlyArray<any>): T {
const id = arguments[3] // generated by compiler
const { pathname, query } = useRouter()
const [data, setData] = useState(() => {
const global = window as any
const useDenoUrl = `useDeno://${pathname}?${query.toString()}`
const { [`__asyncData_${useDenoUrl}`]: asyncData } = global
const key = `${useDenoUrl}#${id}`
if (asyncData && key in asyncData) {
return asyncData[key]
} else if (typeof Deno !== 'undefined' && Deno.version.deno) {
const ret = callback()
if (ret instanceof Promise) {
events.emit(useDenoUrl, id, ret.then(data => {
if (asyncData) {
asyncData[key] = data
}
events.emit(useDenoUrl, id, data)
}), true)
throw new AsyncUseDenoError('async useDeno')
} else {
if (asyncData) {
asyncData[key] = ret
}
events.emit(useDenoUrl, id, ret)
return ret
}
}
return global[key] || null
})
useEffect(() => {
if (browser) {
const ret = callback()
if (ret instanceof Promise) {
ret.then(setData)
} else {
setData(ret)
}
}
}, deps)
return data
}
/**
* `withDeno` allows you to use `useDeno` hook with class component.
*
* ```javascript
* class MyComponent extends React.Component {
* render() {
* return <p>{this.props.version.deno}</p>
* }
* }
* export default withDeno(() => Deno.version)(MyComponent)
* ```
*/
export function withDeno<T>(callback: () => (T | Promise<T>), browser?: boolean, deps?: ReadonlyArray<any>) {
return function <P extends T>(Component: React.ComponentType<P>): React.ComponentType<Exclude<P, keyof T>> {
return function WithDeno(props: Exclude<P, keyof T>) {
const denoProps = useDeno(callback, browser, deps)
if (typeof denoProps === 'object') {
return React.createElement(Component, { ...props, ...denoProps })
}
return React.createElement(Component, props)
}
}
}