自定义 hooks 记录
记录一下常用的自定义 hook~~~
useForceUpdate
当我们使用React.PureComponent
定义类组件的时候,因为React.PureComponent
只是对数据做浅比较,当数据结构非常复杂的情况则可能出现数据更新页面不更新的情况,react 提供了一个forceupdate
方法用来手动重新渲染组件,而函数组件是没有这个方法的,如果也想要实现手动刷新组件可以通过自定义 hook 的方法去实现;
以下记录了两种实现 useForceUpdate 自定义 hook 的方法:
useState 版
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import { useState, useCallback } from 'react'
const useForceUpdate = function (): Function { const [, setCount] = useState < number > 0 const update = useCallback(() => { setCount((prev: number): number => prev + 1) }, [])
return update }
export default useForceUpdate
|
useReducer 版
1 2 3 4 5 6 7 8 9 10 11 12
| import { useReducer } from 'react'
const useForceUpdate = function (): Function { const [, forceUpdate] = useReducer((v: number): number => v + 1, 0) return forceUpdate }
export default useForceUpdate
|
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| ...
const updater = useForceUpdate()
...
const handleRefresh = ():void => { updater() }
...
return( <div> <button onClick={handleRefresh}>refresh</button> </div>)
...
|
useClientRect
动态获取元素大小的自定义 hook
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
| import { useRef, useState, useCallback, RefObject, useLayoutEffect } from 'react' import debounce from 'lodash/debounce'
export const CLIENT_RECT_DEBOUNCE_INTERVAL = 200
function useClientRect<T extends HTMLElement>( debounceInterval: number = CLIENT_RECT_DEBOUNCE_INTERVAL, realtime: boolean = false ): [DOMRect, RefObject<T>] {
const ref = useRef<T>(null) const [rect, setRect] = useState<DOMRect>(null)
const resize = useCallback( debounce(() => { if (ref.current) { setRect(ref.current.getBoundingClientRect()) } }, debounceInterval), [ref.current, realtime] )
useLayoutEffect(() => { if (!ref.current) { return } resize() if (typeof ResizeObserver === 'function') { let resizeObserver = new ResizeObserver(resize) resizeObserver.observe(ref.current) return () => { resizeObserver.disconnect() resizeObserver = null } } else { window.addEventListener('resize', resize) return () => { window.removeEventListener('resize', resize) } } }, [ref.current])
return [rect, ref] }
export default useClientRect
|
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| ...
const [rect, refBackground] = useClientRect<HTMLDivElement>()
useEffect((): void => { console.log('rect',rect) }, [rect])
... return( <div ref={refBackground} className={style.box}> 需要监听的元素 </div> ) ...
|