useMemo与防抖函数的依赖数组问题及代码优化咨询
问题原因分析
- 第一个错误根源:
getDimensions是组件每次渲染时都会重新创建的新函数,将其作为useMemo的依赖,会导致useMemo每次渲染都重新执行——相当于防抖函数失效,每次都会生成新的防抖实例,根本起不到防抖作用。 - 第二个错误根源:React Hooks的规则明确要求
useMemo必须传递依赖数组,要么传空数组(表示仅执行一次),要么传实际依赖的变量,不传则触发告警。
无告警优化方案
下面提供两种可行的优化方案,同时修复原代码中useEffect未清理监听的内存泄漏问题:
方案一:将getDimensions移入useMemo回调
直接在useMemo内部定义getDimensions,避免将其作为外部依赖,同时保证防抖函数仅创建一次:
// Get Dimensions // Capture dimensions when `App` first mounts, immediately // Listen for resize events and trigger 'getDimensions' (debounced) const handleResize = useMemo(() => { const getDimensions = () => dispatch(setDimensions({ viewportWidth: window.innerWidth, viewportHeight: window.innerHeight })); return debounce(getDimensions, 250); }, [dispatch]) // dispatch来自useDispatch,引用稳定,不会随渲染变化 useEffect(() => { handleResize(); window.addEventListener('resize', handleResize); // 清理监听与防抖队列,避免内存泄漏 return () => { window.removeEventListener('resize', handleResize); handleResize.cancel(); }; }, [handleResize]) // 依赖防抖函数实例,仅在实例变化时重新绑定
方案二:用useCallback包裹getDimensions
通过useCallback让getDimensions的引用保持稳定,作为useMemo的依赖时不会触发不必要的重执行:
// Get Dimensions // Capture dimensions when `App` first mounts, immediately // Listen for resize events and trigger 'getDimensions' (debounced) const getDimensions = useCallback(() => dispatch(setDimensions({ viewportWidth: window.innerWidth, viewportHeight: window.innerHeight })), [dispatch]) // 依赖稳定的dispatch,保证函数引用不变 const handleResize = useMemo(() => debounce(getDimensions, 250) , [getDimensions]) // 现在getDimensions引用稳定,useMemo仅执行一次 useEffect(() => { handleResize(); window.addEventListener('resize', handleResize); return () => { window.removeEventListener('resize', handleResize); handleResize.cancel(); }; }, [handleResize])
额外说明
原代码中的useEffect未添加依赖数组和清理函数,会导致每次渲染都重复绑定resize事件,还会造成内存泄漏,上述方案已同步修复该问题。
内容的提问来源于stack exchange,提问作者singing
相关产品推荐
相关产品推荐

