React如何正确获取图片尺寸并设置父包裹容器大小
问题根因
你当前代码拿不到正确图片尺寸的核心原因是执行时机不对:
- 空依赖的
useLayoutEffect仅在组件DOM首次挂载时执行一次,但<img>的图片资源是异步加载的,effect触发时图片还没完成下载和渲染,此时读到的offsetWidth/offsetHeight是标签占位值(通常是0或者预设的宽高属性值),不是图片真实尺寸。 - 你调试时看到ref上有正确尺寸,是因为调试操作发生在图片加载完成之后,此时ref对象上的值已经更新,但effect早就执行完了,不会再触发setState更新,所以state里存的一直是初始读到的错误值。
正确实现方式
方案1:监听图片onLoad事件(适配你的场景,最简单直接)
图片加载完成后会触发原生load事件,此时读取尺寸一定是准确的,你可以在回调里完成放大计算,再把尺寸同步给父容器:
const targetRef = useRef<HTMLImageElement | null>(null); const [containerSize, setContainerSize] = useState({ width: 0, height: 0 }); // 自定义放大比例 const SCALE_RATIO = 2; const handleImageLoad = () => { const imgEl = targetRef.current; if (!imgEl) return; // 读图片原始固有尺寸(不受CSS样式影响,计算缩放更准确) const originWidth = imgEl.naturalWidth; const originHeight = imgEl.naturalHeight; // 执行放大计算 setContainerSize({ width: originWidth * SCALE_RATIO, height: originHeight * SCALE_RATIO }); }; return ( // 父容器尺寸直接绑定state值 <div className="img-wrapper" style={{ width: containerSize.width, height: containerSize.height }} > <img ref={targetRef} src="你的图片资源地址" onLoad={handleImageLoad} /> </div> );
方案2:用ResizeObserver监听尺寸动态变化
如果你的场景存在图片加载完成后尺寸还会变动的情况(比如窗口缩放、响应式布局调整、动态修改图片src),可以用原生ResizeObserver持续监听图片元素的尺寸变化,自动同步更新状态,不需要依赖load事件:
const targetRef = useRef<HTMLImageElement | null>(null); const [containerSize, setContainerSize] = useState({ width: 0, height: 0 }); const SCALE_RATIO = 2; useLayoutEffect(() => { const imgEl = targetRef.current; if (!imgEl) return; const observer = new ResizeObserver(entries => { for (const entry of entries) { // 拿到元素实时渲染尺寸 const { width, height } = entry.contentRect; setContainerSize({ width: width * SCALE_RATIO, height: height * SCALE_RATIO }); } }); observer.observe(imgEl); // 组件卸载时断开监听,避免内存泄漏 return () => observer.disconnect(); }, []);
注意事项
不要在空依赖的挂载effect里直接读取img、video这类异步加载媒体元素的尺寸,这类元素的真实尺寸必须等资源加载完成后才能拿到,要么监听对应load事件,要么用ResizeObserver做持续监听。
内容的提问来源于stack exchange,提问作者Irina Mysko
相关产品推荐
相关产品推荐

