如何复用React中获取容器动态尺寸的代码?
动态获取容器尺寸的React代码复用方案
问题场景
我正在学习React,需要实现多个依赖容器尺寸的响应式组件。当前单个组件的实现代码如下:
import React, { useEffect, useState, useRef } from "react"; const ComponentOne = () => { const refContainer = useRef(); const [dimensions, setDimensions] = useState({ width: 0, height: 0 }); const handleSize = () => { setDimensions({ width: refContainer.current.offsetWidth, height: refContainer.current.offsetHeight, }); }; /* Run first time */ useEffect(() => { handleSize(); }, []); /* Run on resize */ useEffect(() => { window.addEventListener("resize", handleSize); }, []); /* Some useful code which depends on those dimensions here ..... */ return ( <> <div ref={refContainer}>Something produced by that useful code</div> </> ); }; export default ComponentOne;
现在需要创建5个类似组件,想封装工具函数/模块,传入容器引用返回尺寸。尝试过HOC,但无法处理ref的传递和使用。同时发现第三方库react-cool-dimensions有简洁的实现方式:
const { observe, width, height } = useDimensions();
只需设置ref={observe},加载和resize事件都在内部处理。
解决方案
1. 自定义Hook封装
既然HOC在ref处理上有局限,自定义Hook是更合适的复用方式,完全契合React的Hook复用逻辑,且能轻松处理ref和尺寸监听:
// useContainerDimensions.js import { useState, useCallback } from "react"; export const useContainerDimensions = () => { const [dimensions, setDimensions] = useState({ width: 0, height: 0 }); const ref = useCallback(node => { if (node) { const updateDimensions = () => { setDimensions({ width: node.offsetWidth, height: node.offsetHeight }); }; // 初始化获取尺寸 updateDimensions(); // 监听窗口resize window.addEventListener("resize", updateDimensions); // 组件卸载时清理监听 return () => { window.removeEventListener("resize", updateDimensions); }; } }, []); return { ref, ...dimensions }; };
使用示例:
import { useContainerDimensions } from "./useContainerDimensions"; const ComponentOne = () => { const { ref, width, height } = useContainerDimensions(); /* 依赖width/height的业务代码 */ return ( <div ref={ref}> 当前容器尺寸:宽{width}px,高{height}px </div> ); };
这个Hook的优势:
- 用
useCallback创建ref回调,避免不必要的重渲染 - 自动处理初始化尺寸获取和resize监听
- 组件卸载时自动移除监听,防止内存泄漏
- 直接返回ref和尺寸数据,使用简洁
2. 使用第三方库react-cool-dimensions
如果不想自己维护监听逻辑,react-cool-dimensions是成熟的选择,它不仅处理窗口resize,还支持容器自身尺寸变化(比如子元素撑开容器)、防抖节流等高级功能。
基础使用方式:
import { useDimensions } from "react-cool-dimensions"; const ComponentTwo = () => { const { observe, width, height } = useDimensions({ // 可选配置:防抖时间(单位ms) debounce: 100 }); return ( <div ref={observe}> 容器宽:{width}px,高:{height}px </div> ); };
这个库的核心优势:
- 开箱即用,无需手写监听逻辑
- 支持容器自身尺寸变化的监听(不止窗口resize)
- 内置防抖节流,优化性能
内容的提问来源于stack exchange,提问作者Alex Bachurin
相关产品推荐
相关产品推荐

