🔖 reactreact hooks

useDeepCompareCallback

Deep compare version of React.useCallback

useDeepCompareCallback.ts  | 24 lines.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { isEqual } from '@guanghechen/equal'
import type React from 'react'
import { useCallback, useRef } from 'react'
/**
* Deep compare version of React.useCallback
* @param fn
* @param deps
*/
export function useDeepCompareCallback<T extends (...args: any[]) => any>(
fn: T,
deps: React.DependencyList,
): T {
const signal = useRef<number>(0)
const prevDeps = useRef<React.DependencyList>(deps)
if (!isEqual(prevDeps.current, deps)) {
signal.current += 1
}
prevDeps.current = deps
// eslint-disable-next-line react-hooks/exhaustive-deps
return useCallback(fn, [signal.current])
}

useDeepCompareEffect

Deep compare version of React.useEffect

useDeepCompareEffect.ts  | 21 lines.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { isEqual } from '@guanghechen/equal'
import type React from 'react'
import { useEffect, useRef } from 'react'
/**
* Deep compare version of React.useEffect
* @param fn
* @param deps
*/
export function useDeepCompareEffect(fn: React.EffectCallback, deps: React.DependencyList): void {
const signal = useRef<number>(0)
const prevDeps = useRef<React.DependencyList>(deps)
if (!isEqual(prevDeps.current, deps)) {
signal.current += 1
}
prevDeps.current = deps
// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(fn, [signal.current])
}

useDeepCompareMemo

Deep compare version of React.useMemo

useDeepCompareMemo.ts  | 21 lines.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { isEqual } from '@guanghechen/equal'
import type React from 'react'
import { useMemo, useRef } from 'react'
/**
* Deep compare version of React.useMemo
* @param fn
* @param deps
*/
export function useDeepCompareMemo<T>(fn: () => T, deps: React.DependencyList): T {
const signal = useRef<number>(0)
const prevDeps = useRef<React.DependencyList>(deps)
if (!isEqual(prevDeps.current, deps)) {
signal.current += 1
}
prevDeps.current = deps
// eslint-disable-next-line react-hooks/exhaustive-deps
return useMemo(fn, [signal.current])
}

useInterval

Execute callback interval in react function components.

userInterval.ts  | 25 lines.
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
import { useEffect, useRef } from 'react'
type Callback = () => void
/**
* Execute callback interval in react function components.
* @param callback
* @param delay
*/
export function useInterval(callback: Callback, delay: number): void {
const callbackRef = useRef<Callback>(callback)
useEffect(() => {
callbackRef.current = callback
}, [callback])
useEffect(() => {
const tick: Callback = () => {
if (callbackRef.current === undefined) return
callbackRef.current()
}
const id = setInterval(tick, delay)
return () => clearInterval(id)
}, [delay])
}

usePreviousState

记录上一个状态。

利用更新 ref.current 的值不会触发组件更新的特性,在 usePreviousState 中总是返回旧的值,尽管在 userPreviousStateuseEffect 中更新了新值,但并不触发更新。

usePreviousState.ts  | 14 lines.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { useEffect, useRef } from 'react'
/**
* Use previous state.
* @param value
* @returns
*/
export function usePreviousState<T = unknown>(value: T): T {
const ref = useRef<T>(value)
useEffect(() => {
ref.current = value
}, [value])
return ref.current
}

useReactiveRef

useReactiveRef.ts  | 15 lines.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import type React from 'react'
import { useEffect, useRef } from 'react'
/**
* Create a reactive ref which will follow the changes of the given data.
* @param data
* @returns
*/
export function useReactiveRef<T>(data: T): React.MutableRefObject<T> {
const ref = useRef(data)
useEffect(() => {
ref.current = data
}, [data])
return ref
}

Example

demo/usePreviousState.jsx 
0

before: -1

© 2017-2025 光和尘有花满渚、有酒盈瓯

Comments