React中如何使用useRef动态更新组件height属性?
解决方案
核心问题说明
- 初始化阶段DOM尚未完成挂载,ref未绑定真实元素,直接读取offsetHeight会得到undefined
- tab切换后React状态更新是异步批量执行的,直接读取DOM拿到的是上一个tab的内容高度,不是最新渲染的内容高度
- 未在DOM更新完成的时机触发高度重新计算
完整实现代码
import { useState, useRef, useEffect } from 'react'; function App() { const [tab, setTab] = useState(0); // 绑定内层tab内容容器的ref const contentRef = useRef(null); // 存储动态计算的容器高度 const [height, setHeight] = useState(0); const switchTab = (id) => { setTab(id); }; // 监听tab变化,DOM更新完成后重新计算内容高度 useEffect(() => { if (contentRef.current) { setHeight(contentRef.current.offsetHeight); } }, [tab]); return ( <div style={{ margin: '100px auto', backgroundColor: 'pink', width: '400px', overflow: 'hidden', height: `${height}px`, // 绑定动态计算的高度 transition: 'height 0.3s' // 可选:增加高度过渡动画,交互更流畅 }} > {/* 内层内容容器绑定ref,用于读取实际内容高度 */} <div ref={contentRef}> {tab === 0 && ( <div style={{ display: 'flex', flexDirection: 'column' }}> <h2>Tab 1</h2> <input /> <button onClick={() => switchTab(1)}>Go to tab 2</button> <p>Some text here</p> </div> )} {tab === 1 && ( <div style={{ display: 'flex', flexDirection: 'column' }}> <h2>Tab 2</h2> <input /> <button onClick={() => switchTab(0)}>Go to tab 1</button> <button onClick={() => switchTab(2)}>Go to tab 3</button> <p> Some more text here. Some more text here. Some more text here. Some more text here. Some more text here. Some more text here. Some more text here </p> </div> )} {tab === 2 && ( <div style={{ display: 'flex', flexDirection: 'column' }}> <h2>Tab 3</h2> <input /> <button onClick={() => switchTab(0)}>Go to tab 1</button> <button onClick={() => switchTab(1)}>Go to tab 2</button> </div> )} </div> </div> ); }
实现逻辑说明
- 将ref绑定到未固定高度的内层内容容器,而非外层需要设置高度的容器
- 依赖tab状态作为useEffect的触发条件,useEffect会在DOM更新完成后执行,此时读取到的contentRef高度就是当前tab内容的真实高度
- 读取高度前增加非空判断,避免ref未挂载时读取属性报错
内容的提问来源于stack exchange,提问作者qweezz
相关产品推荐
相关产品推荐

