@take-out/hooks 0.0.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +120 -0
- package/dist/cjs/index.cjs +30 -0
- package/dist/cjs/index.js +27 -0
- package/dist/cjs/index.js.map +6 -0
- package/dist/cjs/index.native.js +33 -0
- package/dist/cjs/index.native.js.map +1 -0
- package/dist/cjs/useClickOutside.cjs +43 -0
- package/dist/cjs/useClickOutside.js +37 -0
- package/dist/cjs/useClickOutside.js.map +6 -0
- package/dist/cjs/useClickOutside.native.js +51 -0
- package/dist/cjs/useClickOutside.native.js.map +1 -0
- package/dist/cjs/useDebouncePrepend.cjs +46 -0
- package/dist/cjs/useDebouncePrepend.js +40 -0
- package/dist/cjs/useDebouncePrepend.js.map +6 -0
- package/dist/cjs/useDebouncePrepend.native.js +54 -0
- package/dist/cjs/useDebouncePrepend.native.js.map +1 -0
- package/dist/cjs/useDeepMemoizedObject.cjs +148 -0
- package/dist/cjs/useDeepMemoizedObject.js +122 -0
- package/dist/cjs/useDeepMemoizedObject.js.map +6 -0
- package/dist/cjs/useDeepMemoizedObject.native.js +192 -0
- package/dist/cjs/useDeepMemoizedObject.native.js.map +1 -0
- package/dist/cjs/useDeepMemoizedObject.test.cjs +251 -0
- package/dist/cjs/useDeepMemoizedObject.test.js +187 -0
- package/dist/cjs/useDeepMemoizedObject.test.js.map +6 -0
- package/dist/cjs/useDeepMemoizedObject.test.native.js +261 -0
- package/dist/cjs/useDeepMemoizedObject.test.native.js.map +1 -0
- package/dist/cjs/useDeferredBoolean.cjs +34 -0
- package/dist/cjs/useDeferredBoolean.js +29 -0
- package/dist/cjs/useDeferredBoolean.js.map +6 -0
- package/dist/cjs/useDeferredBoolean.native.js +37 -0
- package/dist/cjs/useDeferredBoolean.native.js.map +1 -0
- package/dist/cjs/useEffectOnceGlobally.cjs +33 -0
- package/dist/cjs/useEffectOnceGlobally.js +28 -0
- package/dist/cjs/useEffectOnceGlobally.js.map +6 -0
- package/dist/cjs/useEffectOnceGlobally.native.js +38 -0
- package/dist/cjs/useEffectOnceGlobally.native.js.map +1 -0
- package/dist/cjs/useIsMounted.cjs +32 -0
- package/dist/cjs/useIsMounted.js +27 -0
- package/dist/cjs/useIsMounted.js.map +6 -0
- package/dist/cjs/useIsMounted.native.js +35 -0
- package/dist/cjs/useIsMounted.native.js.map +1 -0
- package/dist/cjs/useLastValue.cjs +29 -0
- package/dist/cjs/useLastValue.js +24 -0
- package/dist/cjs/useLastValue.js.map +6 -0
- package/dist/cjs/useLastValue.native.js +32 -0
- package/dist/cjs/useLastValue.native.js.map +1 -0
- package/dist/cjs/useLastValueIf.cjs +31 -0
- package/dist/cjs/useLastValueIf.js +25 -0
- package/dist/cjs/useLastValueIf.js.map +6 -0
- package/dist/cjs/useLastValueIf.native.js +35 -0
- package/dist/cjs/useLastValueIf.native.js.map +1 -0
- package/dist/cjs/useMemoStable.cjs +32 -0
- package/dist/cjs/useMemoStable.js +26 -0
- package/dist/cjs/useMemoStable.js.map +6 -0
- package/dist/cjs/useMemoStable.native.js +36 -0
- package/dist/cjs/useMemoStable.native.js.map +1 -0
- package/dist/cjs/useMemoizedObjectList.cjs +48 -0
- package/dist/cjs/useMemoizedObjectList.js +36 -0
- package/dist/cjs/useMemoizedObjectList.js.map +6 -0
- package/dist/cjs/useMemoizedObjectList.native.js +65 -0
- package/dist/cjs/useMemoizedObjectList.native.js.map +1 -0
- package/dist/cjs/useThrottle.cjs +39 -0
- package/dist/cjs/useThrottle.js +30 -0
- package/dist/cjs/useThrottle.js.map +6 -0
- package/dist/cjs/useThrottle.native.js +45 -0
- package/dist/cjs/useThrottle.native.js.map +1 -0
- package/dist/cjs/useWarnIfDepsChange.cjs +54 -0
- package/dist/cjs/useWarnIfDepsChange.js +46 -0
- package/dist/cjs/useWarnIfDepsChange.js.map +6 -0
- package/dist/cjs/useWarnIfDepsChange.native.js +58 -0
- package/dist/cjs/useWarnIfDepsChange.native.js.map +1 -0
- package/dist/cjs/useWarnIfMemoChangesOften.cjs +34 -0
- package/dist/cjs/useWarnIfMemoChangesOften.js +29 -0
- package/dist/cjs/useWarnIfMemoChangesOften.js.map +6 -0
- package/dist/cjs/useWarnIfMemoChangesOften.native.js +42 -0
- package/dist/cjs/useWarnIfMemoChangesOften.native.js.map +1 -0
- package/dist/esm/index.js +14 -0
- package/dist/esm/index.js.map +6 -0
- package/dist/esm/index.mjs +14 -0
- package/dist/esm/index.mjs.map +1 -0
- package/dist/esm/index.native.js +14 -0
- package/dist/esm/index.native.js.map +1 -0
- package/dist/esm/useClickOutside.js +22 -0
- package/dist/esm/useClickOutside.js.map +6 -0
- package/dist/esm/useClickOutside.mjs +20 -0
- package/dist/esm/useClickOutside.mjs.map +1 -0
- package/dist/esm/useClickOutside.native.js +25 -0
- package/dist/esm/useClickOutside.native.js.map +1 -0
- package/dist/esm/useDebouncePrepend.js +25 -0
- package/dist/esm/useDebouncePrepend.js.map +6 -0
- package/dist/esm/useDebouncePrepend.mjs +23 -0
- package/dist/esm/useDebouncePrepend.mjs.map +1 -0
- package/dist/esm/useDebouncePrepend.native.js +28 -0
- package/dist/esm/useDebouncePrepend.native.js.map +1 -0
- package/dist/esm/useDeepMemoizedObject.js +106 -0
- package/dist/esm/useDeepMemoizedObject.js.map +6 -0
- package/dist/esm/useDeepMemoizedObject.mjs +123 -0
- package/dist/esm/useDeepMemoizedObject.mjs.map +1 -0
- package/dist/esm/useDeepMemoizedObject.native.js +164 -0
- package/dist/esm/useDeepMemoizedObject.native.js.map +1 -0
- package/dist/esm/useDeepMemoizedObject.test.js +188 -0
- package/dist/esm/useDeepMemoizedObject.test.js.map +6 -0
- package/dist/esm/useDeepMemoizedObject.test.mjs +252 -0
- package/dist/esm/useDeepMemoizedObject.test.mjs.map +1 -0
- package/dist/esm/useDeepMemoizedObject.test.native.js +259 -0
- package/dist/esm/useDeepMemoizedObject.test.native.js.map +1 -0
- package/dist/esm/useDeferredBoolean.js +13 -0
- package/dist/esm/useDeferredBoolean.js.map +6 -0
- package/dist/esm/useDeferredBoolean.mjs +11 -0
- package/dist/esm/useDeferredBoolean.mjs.map +1 -0
- package/dist/esm/useDeferredBoolean.native.js +11 -0
- package/dist/esm/useDeferredBoolean.native.js.map +1 -0
- package/dist/esm/useEffectOnceGlobally.js +12 -0
- package/dist/esm/useEffectOnceGlobally.js.map +6 -0
- package/dist/esm/useEffectOnceGlobally.mjs +10 -0
- package/dist/esm/useEffectOnceGlobally.mjs.map +1 -0
- package/dist/esm/useEffectOnceGlobally.native.js +12 -0
- package/dist/esm/useEffectOnceGlobally.native.js.map +1 -0
- package/dist/esm/useIsMounted.js +11 -0
- package/dist/esm/useIsMounted.js.map +6 -0
- package/dist/esm/useIsMounted.mjs +9 -0
- package/dist/esm/useIsMounted.mjs.map +1 -0
- package/dist/esm/useIsMounted.native.js +9 -0
- package/dist/esm/useIsMounted.native.js.map +1 -0
- package/dist/esm/useLastValue.js +8 -0
- package/dist/esm/useLastValue.js.map +6 -0
- package/dist/esm/useLastValue.mjs +6 -0
- package/dist/esm/useLastValue.mjs.map +1 -0
- package/dist/esm/useLastValue.native.js +6 -0
- package/dist/esm/useLastValue.native.js.map +1 -0
- package/dist/esm/useLastValueIf.js +9 -0
- package/dist/esm/useLastValueIf.js.map +6 -0
- package/dist/esm/useLastValueIf.mjs +8 -0
- package/dist/esm/useLastValueIf.mjs.map +1 -0
- package/dist/esm/useLastValueIf.native.js +9 -0
- package/dist/esm/useLastValueIf.native.js.map +1 -0
- package/dist/esm/useMemoStable.js +11 -0
- package/dist/esm/useMemoStable.js.map +6 -0
- package/dist/esm/useMemoStable.mjs +9 -0
- package/dist/esm/useMemoStable.mjs.map +1 -0
- package/dist/esm/useMemoStable.native.js +10 -0
- package/dist/esm/useMemoStable.native.js.map +1 -0
- package/dist/esm/useMemoizedObjectList.js +21 -0
- package/dist/esm/useMemoizedObjectList.js.map +6 -0
- package/dist/esm/useMemoizedObjectList.mjs +25 -0
- package/dist/esm/useMemoizedObjectList.mjs.map +1 -0
- package/dist/esm/useMemoizedObjectList.native.js +39 -0
- package/dist/esm/useMemoizedObjectList.native.js.map +1 -0
- package/dist/esm/useThrottle.js +15 -0
- package/dist/esm/useThrottle.js.map +6 -0
- package/dist/esm/useThrottle.mjs +16 -0
- package/dist/esm/useThrottle.mjs.map +1 -0
- package/dist/esm/useThrottle.native.js +19 -0
- package/dist/esm/useThrottle.native.js.map +1 -0
- package/dist/esm/useWarnIfDepsChange.js +31 -0
- package/dist/esm/useWarnIfDepsChange.js.map +6 -0
- package/dist/esm/useWarnIfDepsChange.mjs +31 -0
- package/dist/esm/useWarnIfDepsChange.mjs.map +1 -0
- package/dist/esm/useWarnIfDepsChange.native.js +32 -0
- package/dist/esm/useWarnIfDepsChange.native.js.map +1 -0
- package/dist/esm/useWarnIfMemoChangesOften.js +14 -0
- package/dist/esm/useWarnIfMemoChangesOften.js.map +6 -0
- package/dist/esm/useWarnIfMemoChangesOften.mjs +11 -0
- package/dist/esm/useWarnIfMemoChangesOften.mjs.map +1 -0
- package/dist/esm/useWarnIfMemoChangesOften.native.js +16 -0
- package/dist/esm/useWarnIfMemoChangesOften.native.js.map +1 -0
- package/package.json +54 -0
- package/src/index.ts +13 -0
- package/src/useClickOutside.ts +34 -0
- package/src/useDebouncePrepend.ts +63 -0
- package/src/useDeepMemoizedObject.test.ts +343 -0
- package/src/useDeepMemoizedObject.ts +231 -0
- package/src/useDeferredBoolean.tsx +15 -0
- package/src/useEffectOnceGlobally.ts +41 -0
- package/src/useIsMounted.ts +11 -0
- package/src/useLastValue.ts +5 -0
- package/src/useLastValueIf.ts +15 -0
- package/src/useMemoStable.ts +24 -0
- package/src/useMemoizedObjectList.ts +74 -0
- package/src/useThrottle.ts +35 -0
- package/src/useWarnIfDepsChange.ts +61 -0
- package/src/useWarnIfMemoChangesOften.ts +24 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { useEffect } from 'react'
|
|
2
|
+
|
|
3
|
+
const executedKeys = new Set<string>()
|
|
4
|
+
|
|
5
|
+
type WithId = { id: string }
|
|
6
|
+
|
|
7
|
+
type KeyType<T> = string | string[] | WithId | WithId[] | readonly WithId[] | undefined
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Hook that ensures an effect only runs once globally across all component instances
|
|
11
|
+
* Uses a key (or array of keys) to determine if the effect has already been executed
|
|
12
|
+
*/
|
|
13
|
+
export function useEffectOnceGlobally<T extends KeyType<T>>(
|
|
14
|
+
key: T,
|
|
15
|
+
callback: T extends undefined ? () => void : (value: NonNullable<T>) => void
|
|
16
|
+
) {
|
|
17
|
+
const keyString = !key
|
|
18
|
+
? undefined
|
|
19
|
+
: typeof key === 'string'
|
|
20
|
+
? key
|
|
21
|
+
: Array.isArray(key)
|
|
22
|
+
? typeof key[0] === 'string'
|
|
23
|
+
? (key as string[]).sort().join('')
|
|
24
|
+
: (key as readonly WithId[])
|
|
25
|
+
.map((item) => item.id)
|
|
26
|
+
.sort()
|
|
27
|
+
.join('')
|
|
28
|
+
: (key as WithId).id
|
|
29
|
+
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
if (!keyString || executedKeys.has(keyString)) {
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
executedKeys.add(keyString)
|
|
35
|
+
if (key !== undefined) {
|
|
36
|
+
;(callback as (value: NonNullable<T>) => void)(key as NonNullable<T>)
|
|
37
|
+
} else {
|
|
38
|
+
;(callback as () => void)()
|
|
39
|
+
}
|
|
40
|
+
}, [keyString, callback, key])
|
|
41
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useRef } from 'react'
|
|
2
|
+
|
|
3
|
+
export function useLastValueIf<T>(value: T, keepLast = true): T | undefined {
|
|
4
|
+
// sorted [newest, older]
|
|
5
|
+
const lastTwoValuesRef = useRef<(T | undefined)[]>([])
|
|
6
|
+
|
|
7
|
+
const [latest] = lastTwoValuesRef.current
|
|
8
|
+
if (keepLast) {
|
|
9
|
+
if (latest !== value) {
|
|
10
|
+
lastTwoValuesRef.current = [value, latest]
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return lastTwoValuesRef.current[1]
|
|
15
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { useMemo } from 'react'
|
|
2
|
+
import { useWarnIfDepsChange } from './useWarnIfDepsChange'
|
|
3
|
+
|
|
4
|
+
// create a useMemo that can log when it changes too often
|
|
5
|
+
// useful for development
|
|
6
|
+
|
|
7
|
+
export interface UseMemoStableOptions {
|
|
8
|
+
maxChanges?: number
|
|
9
|
+
ignoreIndexBefore?: number
|
|
10
|
+
name: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function useMemoStable<Value, T extends readonly unknown[]>(
|
|
14
|
+
getValue: () => Value,
|
|
15
|
+
deps: T,
|
|
16
|
+
options: UseMemoStableOptions = {
|
|
17
|
+
name: `(untitled)`,
|
|
18
|
+
}
|
|
19
|
+
): Value {
|
|
20
|
+
useWarnIfDepsChange(deps, options)
|
|
21
|
+
|
|
22
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: ignore
|
|
23
|
+
return useMemo(getValue, deps)
|
|
24
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { useEffect, useMemo, useRef } from 'react'
|
|
2
|
+
import { isEqualDeepLite } from '@take-out/helpers'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* When zero mutates and inserts, it creates all new objects for everything, but this
|
|
6
|
+
* breaks react memoization, even when only the last item is mutated, or the last item
|
|
7
|
+
* is inserted. This hook should be considered temporary, I've brought up the idea with
|
|
8
|
+
* the zero team to implement this internally, as that would be significantly faster.
|
|
9
|
+
*
|
|
10
|
+
* for now, this basically will re-use the last message if JSON.stringify says its the same
|
|
11
|
+
* that way you skip a lot of re-rendering work when changing long lists of items
|
|
12
|
+
*
|
|
13
|
+
* NOTE: this leaks memory
|
|
14
|
+
*/
|
|
15
|
+
export function useMemoizedObjectList<
|
|
16
|
+
Items extends readonly Object[],
|
|
17
|
+
Item extends Items[0] = Items[0],
|
|
18
|
+
ItemKey extends keyof Item = keyof Item,
|
|
19
|
+
>(list: Items, identityKey: ItemKey): Items {
|
|
20
|
+
const memoizedItems = useRef<Record<string, any>>({})
|
|
21
|
+
const memoizedList = useRef<Items>(list)
|
|
22
|
+
|
|
23
|
+
const val = useMemo(() => {
|
|
24
|
+
let res = list
|
|
25
|
+
let didFindChange = false
|
|
26
|
+
const next = []
|
|
27
|
+
const lastItems = memoizedItems.current
|
|
28
|
+
|
|
29
|
+
// changed size, always update array identity
|
|
30
|
+
if (list.length !== memoizedList.current.length) {
|
|
31
|
+
didFindChange = true
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
for (const item_ of list) {
|
|
35
|
+
const item = item_ as Item
|
|
36
|
+
const id = item[identityKey] as any
|
|
37
|
+
const last = lastItems[id]
|
|
38
|
+
|
|
39
|
+
// zero is returning a symbol on objects sometimes?
|
|
40
|
+
if (!last || !isEqualDeepLite(last, item)) {
|
|
41
|
+
didFindChange = true
|
|
42
|
+
|
|
43
|
+
// if (last) {
|
|
44
|
+
// console.info(`did change`, item, 'vs', last)
|
|
45
|
+
// for (const key in item) {
|
|
46
|
+
// if (!deepEqualLite(item[key], last[key])) {
|
|
47
|
+
// console.warn('changed', key)
|
|
48
|
+
// }
|
|
49
|
+
// }
|
|
50
|
+
// }
|
|
51
|
+
|
|
52
|
+
lastItems[id] = item
|
|
53
|
+
next.push(item)
|
|
54
|
+
} else {
|
|
55
|
+
next.push(last)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// if every item matches we can memoize the entire array
|
|
60
|
+
if (didFindChange) {
|
|
61
|
+
res = next as any
|
|
62
|
+
} else {
|
|
63
|
+
res = memoizedList.current
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return res
|
|
67
|
+
}, [identityKey, list])
|
|
68
|
+
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
memoizedList.current = val
|
|
71
|
+
}, [val])
|
|
72
|
+
|
|
73
|
+
return val
|
|
74
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { useRef } from 'react'
|
|
2
|
+
import { useEvent } from 'tamagui'
|
|
3
|
+
|
|
4
|
+
type Timer = ReturnType<typeof setTimeout>
|
|
5
|
+
|
|
6
|
+
export const useThrottle = <T extends (...args: any[]) => any>(fn: T, delay = 100): T => {
|
|
7
|
+
const lastCallTime = useRef<number>(0)
|
|
8
|
+
const timeoutRef = useRef<Timer | null>(null)
|
|
9
|
+
|
|
10
|
+
const stableFn = useEvent(fn)
|
|
11
|
+
|
|
12
|
+
const throttledFn = useEvent((...args: Parameters<T>) => {
|
|
13
|
+
const now = Date.now()
|
|
14
|
+
const timeSinceLastCall = now - lastCallTime.current
|
|
15
|
+
|
|
16
|
+
if (timeSinceLastCall >= delay) {
|
|
17
|
+
// If enough time has passed, call immediately
|
|
18
|
+
lastCallTime.current = now
|
|
19
|
+
stableFn(...args)
|
|
20
|
+
} else {
|
|
21
|
+
// Otherwise, schedule a call for when the delay period is over
|
|
22
|
+
if (timeoutRef.current) {
|
|
23
|
+
clearTimeout(timeoutRef.current)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
timeoutRef.current = setTimeout(() => {
|
|
27
|
+
lastCallTime.current = Date.now()
|
|
28
|
+
stableFn(...args)
|
|
29
|
+
timeoutRef.current = null
|
|
30
|
+
}, delay - timeSinceLastCall)
|
|
31
|
+
}
|
|
32
|
+
}) as T
|
|
33
|
+
|
|
34
|
+
return throttledFn
|
|
35
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { useEffect, useId, useRef } from 'react'
|
|
2
|
+
import { getCurrentComponentStack } from '@take-out/helpers'
|
|
3
|
+
|
|
4
|
+
export interface UseWarnIfDepsChangeOptions {
|
|
5
|
+
maxChanges?: number
|
|
6
|
+
ignoreIndexBefore?: number
|
|
7
|
+
name: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function useWarnIfDepsChange<T extends readonly unknown[]>(
|
|
11
|
+
deps: T,
|
|
12
|
+
options: UseWarnIfDepsChangeOptions
|
|
13
|
+
): void {
|
|
14
|
+
const { maxChanges = 0, name, ignoreIndexBefore = 0 } = options
|
|
15
|
+
|
|
16
|
+
const changeCountRef = useRef(0)
|
|
17
|
+
const prevDepsRef = useRef<T | undefined>(undefined)
|
|
18
|
+
const id = useId()
|
|
19
|
+
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
if (process.env.NODE_ENV === 'development') {
|
|
22
|
+
if (prevDepsRef.current !== undefined) {
|
|
23
|
+
const changedDeps: Array<{
|
|
24
|
+
index: number
|
|
25
|
+
prev: unknown
|
|
26
|
+
next: unknown
|
|
27
|
+
}> = []
|
|
28
|
+
|
|
29
|
+
const compareDeps = ignoreIndexBefore ? deps.slice(ignoreIndexBefore) : deps
|
|
30
|
+
|
|
31
|
+
compareDeps.forEach((dep, indexIn) => {
|
|
32
|
+
const index = indexIn + ignoreIndexBefore
|
|
33
|
+
|
|
34
|
+
if (prevDepsRef.current && prevDepsRef.current[index] !== dep) {
|
|
35
|
+
changedDeps.push({
|
|
36
|
+
index,
|
|
37
|
+
prev: prevDepsRef.current[index],
|
|
38
|
+
next: dep,
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
if (changedDeps.length > 0) {
|
|
44
|
+
changeCountRef.current++
|
|
45
|
+
|
|
46
|
+
if (changeCountRef.current > maxChanges) {
|
|
47
|
+
// don't use warn because it adds a huge stack
|
|
48
|
+
console.info(
|
|
49
|
+
`🔄 useWarnIfDepsChange "${name}" is changing too often! Changed ${changeCountRef.current} times (max: ${maxChanges})`,
|
|
50
|
+
changedDeps,
|
|
51
|
+
`\n id (${id}) at:`,
|
|
52
|
+
getCurrentComponentStack('short')
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
prevDepsRef.current = deps
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react'
|
|
2
|
+
import { emptyFn } from '@take-out/helpers'
|
|
3
|
+
|
|
4
|
+
export const useWarnIfMemoChangesOften =
|
|
5
|
+
process.env.NODE_ENV === 'production'
|
|
6
|
+
? (emptyFn as never)
|
|
7
|
+
: <T>(value: T, threshold = 5, name?: string) => {
|
|
8
|
+
const countRef = useRef(0)
|
|
9
|
+
const prevValueRef = useRef<T>(value)
|
|
10
|
+
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
if (prevValueRef.current !== value) {
|
|
13
|
+
countRef.current++
|
|
14
|
+
prevValueRef.current = value
|
|
15
|
+
|
|
16
|
+
if (countRef.current > threshold) {
|
|
17
|
+
const warningName = name || 'Memoized value'
|
|
18
|
+
console.warn(
|
|
19
|
+
`🔄 ${warningName} is changing too often! Changed ${countRef.current} times (threshold: ${threshold})`
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}, [value, threshold, name])
|
|
24
|
+
}
|