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
相关产品推荐
相关产品推荐

