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

React折叠组件useState初始为true时获取scrollHeight报错如何解决

问题原因

React组件的ref会在DOM挂载完成之后才会被赋值为真实DOM节点,而组件首次渲染执行return内的渲染逻辑时,parentRef.current还是初始的undefined状态。
你之前将useState初始值设为false时,渲染逻辑走的是height: "0px"的分支,不会访问parentRef.current,所以不会报错。当你把初始值改为true后,首次渲染直接进入读取scrollHeight的分支,此时ref还未完成赋值,自然就触发了读取undefined属性的报错。

解决方案

推荐将高度计算逻辑移到DOM挂载完成后执行的useEffect中,避免在渲染阶段直接访问未就绪的ref,示例代码如下:

import { useState, useRef, useEffect } from 'react';

function Collapse(props) {
  const [isOpen, setIsOpen] = useState(true);
  const [contentHeight, setContentHeight] = useState('0px');
  const parentRef = useRef(null);

  // 组件挂载、展开状态变化、内容变化时,重新计算内容高度
  useEffect(() => {
    if (!parentRef.current) return;
    setContentHeight(isOpen ? `${parentRef.current.scrollHeight}px` : '0px');
  }, [isOpen, props.children]);

  return (
    <div className="collapse">
      <div className="collapse-toggle" onClick={() => setIsOpen(!isOpen)}>
        {props.label}
      </div>
      <div
        className="collapse-content-parent"
        ref={parentRef}
        style={{ height: contentHeight, overflow: 'hidden' }}
      >
        <div className="collapse-content">{props.children}</div>
      </div>
    </div>
  );
}

export default Collapse;

如果你不想额外维护高度状态,也可以直接在渲染阶段加可选链做兜底,避免报错:

style={
  isOpen
    ? {
        height: parentRef.current?.scrollHeight ? `${parentRef.current.scrollHeight}px` : 'auto',
        overflow: 'hidden'
      }
    : {
        height: '0px',
        overflow: 'hidden'
      }
}

注:第二种兜底方案首次渲染会先使用auto高度,等ref挂载完成后二次渲染才会赋值具体的像素高度,不会影响交互,但是会多一次重渲染,性能略差于第一种方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 03:15:04