You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何对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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 11:54:01