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

useState无法修改状态:动态设置tbody高度问题排查

问题分析与修复方案

你遇到的问题主要出在这几个地方,对应的修复方式如下:

错误点1:重复绑定resize事件且未清理

直接在组件函数体里执行window.addEventListener('resize', resizeHolder),会导致每次组件渲染都重复绑定事件,不仅会触发多次逻辑,还会造成内存泄漏。

错误点2:递归调用依赖异步状态更新的DOM

setHeightTbody是异步操作,调用后DOM不会立刻更新,紧接着递归调用positionChecker时,拿到的tfoot.offsetTop还是修改前的旧值,导致递归要么无限执行,要么根本达不到预期的状态更新效果。

错误点3:初始未执行位置检查

只有窗口resize时才会触发位置检查,组件挂载完成后不会自动执行,初始的tbody高度可能和预期不符。

错误点4:未处理ref未挂载的情况

强制将checkVisibilityFoot.current?.offsetTop转为number,当组件还没挂载完成、ref为null时,会得到NaN,导致逻辑判断失效。


修复后的代码示例

.....several imports

const Component= () => {
  const store = useContext(Context);
  const [id, setId] = useState('');
  const [heightTbody, setHeightTbody] = useState(650);
  const checkVisibilityFoot = useRef<HTMLTableSectionElement>(null);
  const [list, setList] = useState<ContentI[]>([]);

  const fetchData = async () => {
    const temp = await store.getContent();
    setList(temp);
  };

  // 重构位置检查逻辑,用requestAnimationFrame确保DOM更新后再检查
  const positionChecker = () => {
    const tfootElement = checkVisibilityFoot.current;
    if (!tfootElement) return;

    const windHeight = window.innerHeight;
    const tfootTop = tfootElement.offsetTop;
    
    if (windHeight < tfootTop) {
      // 调整步长减少状态更新次数,提升性能
      setHeightTbody(prev => prev - 10);
      // 等待DOM更新后再执行下一次检查
      requestAnimationFrame(positionChecker);
    } else if (windHeight > tfootTop + tfootElement.offsetHeight) {
      // 处理窗口变大的情况,让tbody高度自适应
      setHeightTbody(prev => prev + 10);
      requestAnimationFrame(positionChecker);
    }
  };

  const resizeHolder = () => {
    positionChecker();
  };

  useEffect(() => {
    fetchData();
    // 组件挂载后主动执行一次位置检查
    requestAnimationFrame(positionChecker);
    
    // 绑定resize事件并添加清理函数,避免内存泄漏
    window.addEventListener('resize', resizeHolder);
    return () => {
      window.removeEventListener('resize', resizeHolder);
    };
  }, []);

  return (
    <table>
      <tbody style={{ height: `${heightTbody}px`, overflowY: 'auto' }}>
        ......content
      </tbody>
      <tfoot ref={checkVisibilityFoot}></tfoot>
    </table>
  )
}

额外优化建议

  • 给tbody加上overflowY: 'auto',当内容超出设置高度时可以滚动,避免表格内容溢出。
  • 可以给resizeHolder加防抖处理,避免窗口拖动时频繁触发逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 19:15:46