如何修复窗口Resize时出现的Cannot read property 'clientWidth' of null错误?
修复React窗口调整时"Cannot read property 'clientWidth' of null"错误
我帮你梳理下问题根源和修复方案:
问题分析
你遇到的错误主要来自两个核心问题:
- 变量名混乱:代码里混用了
tooltip/setTooltip和allowTooltip/setAllowTooltip,这会直接导致状态更新逻辑失效,甚至让ref的判断逻辑完全出错。 - Ref为空时的属性访问:组件渲染初期、状态切换后,或者组件卸载后,
divRef.current可能还没挂载到DOM(或已被销毁),直接访问它的scrollWidth/clientWidth就会抛出null错误;加上resize事件没有清理,组件卸载后还会触发,进一步加重这个问题。
修复步骤
- 统一变量名:把所有
tooltip替换成allowTooltip,setTooltip替换成setAllowTooltip,保证状态和更新函数一一对应。 - 增加Ref存在性校验:每次访问
divRef.current的属性前,先判断它是否存在,从根源避免null报错。 - 清理Resize事件监听:在
useEffect的返回函数中移除监听,防止组件卸载后触发事件导致错误,同时避免内存泄漏。 - 优化useEffect依赖数组:
divRef是useRef创建的,它的引用不会变化,不需要放到依赖数组里;只需要监听allowTooltip状态即可。
修复后的完整代码
import React, { useRef, useState, useEffect } from "react"; // 这里假设Tooltip是你使用的组件(比如Material-UI的Tooltip或自定义组件) import Tooltip from '@mui/material/Tooltip'; const data = [ "Some short text", "Some text that is a little bit longer", "Some text that will need to wrap but still fits on two lines", "A massive range of hammer drill machines and rotary hammers for SDS-plus accessory tools." ]; const TooltipDiv = props => { const divRef = useRef(null); const [allowTooltip, setAllowTooltip] = useState(false); useEffect(() => { // 把判断逻辑封装成函数,方便复用和移除监听 const checkTextOverflow = () => { // 先校验ref是否存在,再访问DOM属性 if (divRef.current && !allowTooltip) { const hasOverflow = divRef.current.scrollWidth > divRef.current.clientWidth; setAllowTooltip(hasOverflow); } }; // 组件挂载时先检查一次文本是否溢出 checkTextOverflow(); // 添加窗口resize监听 window.addEventListener('resize', checkTextOverflow); // 组件卸载时移除监听,防止内存泄漏和报错 return () => { window.removeEventListener('resize', checkTextOverflow); }; }, [allowTooltip]); // 仅监听allowTooltip状态变化 if (allowTooltip) { return ( <Tooltip title={props.text}> <div ref={divRef} className={props.className}> {props.text} </div> </Tooltip> ); } return ( <div ref={divRef} className={props.className}> {props.text} </div> ); }; function App(props) { return ( <> {data.map((text, index) => { // 给列表元素添加key,符合React列表渲染规范 return ( <TooltipDiv key={index} text={text} className={props.classes?.listItem} /> ); })} </> ); } export default App;
额外优化点
我还补充了两个小细节:
- 给
map循环的元素添加了key属性,符合React的列表渲染规范,避免控制台警告。 - 访问
props.classes.listItem时用了可选链?.,防止props.classes不存在时触发报错。
内容的提问来源于stack exchange,提问作者Marcus
相关产品推荐
相关产品推荐

