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

React中useEffect依赖window.visualViewport.height时不触发更新问题

原因说明

将window.visualViewport.height直接作为useEffect依赖项无法触发更新的核心逻辑是:React的依赖对比机制仅能感知自身渲染流程中产生的状态、props变化,window.visualViewport是浏览器提供的原生全局对象,它的属性变动不会通知React触发重渲染,依赖数组里的这个值只会在组件首次挂载时被读取一次,后续属性值哪怕发生变化,React感知不到,自然不会重新执行effect逻辑。

每秒轮询赋值的写法能运行,本质是通过定时器主动周期性读取原生属性的最新值、强制触发状态更新,但这种方案存在更新延迟、不必要的性能开销,还容易因为忘记清理定时器造成内存泄漏,不推荐在生产环境使用。

最优实现方案

visualViewport原生提供了resize事件,视口尺寸变动(包括iOS端虚拟键盘弹起、收起带来的高度变化)时会主动触发,监听该事件更新状态即可做到实时响应,性能开销极低:

const [viewportHeight, setViewportHeight] = React.useState(0);

React.useEffect(() => {
  const updateViewportHeight = () => {
    setViewportHeight(window.visualViewport.height);
  };
  // 首次挂载时先初始化一次高度
  updateViewportHeight();
  // 绑定视口变化监听
  window.visualViewport.addEventListener('resize', updateViewportHeight);

  // 组件卸载时移除监听,避免内存泄漏
  return () => {
    window.visualViewport.removeEventListener('resize', updateViewportHeight);
  };
}, []);
iOS场景适配提示
  • iOS端虚拟键盘唤起时,window.visualViewport.height会自动扣除虚拟键盘的占用高度,不需要额外获取键盘高度手动计算,适配准确度远高于监听window对象的resize事件(部分iOS版本下键盘唤起不会触发window.resize)。
  • 如果临时使用轮询方案做兼容,一定要在useEffect的返回函数中调用clearInterval清理定时器,避免组件卸载后定时器持续执行引发报错。

内容的提问来源于stack exchange,提问作者Evanss

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 08:48:30