-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
Copy pathuseMemoOne.ts
57 lines (50 loc) · 1.27 KB
/
useMemoOne.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
import { useEffect, useRef, useState, MutableRefObject } from 'react'
type Cache<T> = {
inputs?: any[]
result?: T
}
// TODO: remove once merged (https://github.com/alexreardon/use-memo-one/pull/10)
export function useMemoOne<T>(getResult: () => T, inputs?: any[]): T {
const [initial] = useState(
(): Cache<T> => ({
inputs,
result: getResult(),
})
)
// NOTE: useRef is bugged as immutable in 18.3 types
const committed = useRef<Cache<T>>(null) as MutableRefObject<Cache<T> | null>
const prevCache = committed.current
let cache = prevCache
if (cache) {
const useCache = Boolean(
inputs && cache.inputs && areInputsEqual(inputs, cache.inputs)
)
if (!useCache) {
cache = {
inputs,
result: getResult(),
}
}
} else {
cache = initial
}
useEffect(() => {
committed.current = cache
if (prevCache == initial) {
initial.inputs = initial.result = undefined
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [cache])
return cache.result!
}
function areInputsEqual(next: any[], prev: any[]) {
if (next.length !== prev.length) {
return false
}
for (let i = 0; i < next.length; i++) {
if (next[i] !== prev[i]) {
return false
}
}
return true
}