如何对React自定义Hook的返回值进行记忆化处理?
解决方案
你的需求核心是仅当屏幕尺寸实际跨断点切换时,才更新返回值触发组件重渲染,现有实现的冗余更新来自于useWindowSize会响应每一次宽度变化,哪怕没有命中你设置的尺寸阈值。以下是优化后的完整实现:
优化后代码
import { useState, useEffect } from 'react'; type Sizes = "tiny" | "small" | "medium" | "large"; // 断点配置可根据业务需求灵活调整 const BREAKPOINTS = [ { minWidth: 1184, size: 'large' }, { minWidth: 800, size: 'medium' }, { minWidth: 600, size: 'small' }, { minWidth: 0, size: 'tiny' }, ] as const; // 公共计算逻辑复用 const calcSize = (width: number): Sizes => { for (const { minWidth, size } of BREAKPOINTS) { if (width >= minWidth) return size; } return 'tiny'; }; function useScreenSize(): Sizes { const [size, setSize] = useState<Sizes>(() => { // 初始化直接计算,避免首次渲染返回空值 return typeof window === 'undefined' ? 'medium' : calcSize(window.innerWidth); }); useEffect(() => { const onResize = () => { const newSize = calcSize(window.innerWidth); // 仅当尺寸实际变化时才更新状态,完全避免多余重渲染 setSize(prev => prev === newSize ? prev : newSize); }; window.addEventListener('resize', onResize, { passive: true }); // 兼容SSR hydrate 一致性校验 onResize(); return () => window.removeEventListener('resize', onResize); }, []); return size; }
实现原理
- 移除了对第三方
useWindowSize的依赖,自行监听resize事件,从根源避免每一次宽度变化都触发更新的问题 - 状态更新前增加前后值比对逻辑,只有
tiny/small/medium/large枚举值真实变化时才会触发state更新,调用该Hook的组件也只会在此时重渲染 - 断点配置抽离为常量,后续调整阈值不需要修改核心逻辑,可维护性更强
- 增加了服务端渲染(SSR)兼容逻辑,避免服务端和客户端渲染结果不一致的hydrate报错
进阶优化(多组件共用场景)
如果你的应用内有大量组件调用useScreenSize,可以把尺寸状态放到React Context中全局管理,整个应用只需要监听一次resize事件,所有组件共享同一个尺寸状态,进一步降低事件监听的性能开销。
内容的提问来源于stack exchange,提问作者sina
相关产品推荐
相关产品推荐

