useRafState
作用
只在 requestAnimationFrame callback
时更新 state
,一般用于性能优化
原理
requestAnimationFrame
告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。
源码
ts
import { useCallback, useRef, useState } from 'react'
import type { Dispatch, SetStateAction } from 'react'
import useUnmount from '../useUnmount'
// 函数重载 参数可能是函数,也可能是值,也可能没有传默认值
function useRafState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>]
function useRafState<S = undefined>(): [S | undefined, Dispatch<SetStateAction<S | undefined>>]
function useRafState<S>(initialState?: S | (() => S)) {
// 用来缓存requestAnimationFrame
const ref = useRef(0)
// 用来缓存state,默认是初始化的值
const [state, setState] = useState(initialState)
// 用来更新state
const setRafState = useCallback((value: S | ((prevState: S) => S)) => {
// 先取消上一次的requestAnimationFrame
cancelAnimationFrame(ref.current)
// 重新赋值
ref.current = requestAnimationFrame(() => {
setState(value)
})
}, [])
// 组件卸载时,取消requestAnimationFrame
useUnmount(() => {
cancelAnimationFrame(ref.current)
})
// 返回state和更新state的函数
return [state, setRafState] as const
}
export default useRafState