You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何动态获取React条件渲染组件的高度?

解决条件渲染组件首次显示时基于ref高度的样式不生效问题

你的猜测是对的,问题根源在于React渲染周期与ref挂载的时机差:当你点击按钮切换isClicked为true时,条件渲染的组件会触发首次渲染,但ref的赋值是在DOM节点挂载完成后才执行的。此时你的useEffect依赖ref.current,但首次渲染时ref.current仍为null,导致dimension保持初始值,样式无法生效;直到ref赋值完成后useEffect才会执行更新状态,触发二次渲染,样式才会生效,这就造成了首次显示时的样式异常。

以下是几种可靠的解决方案:

方案1:监听isClicked状态,配合requestAnimationFrame获取尺寸

当isClicked变为true时,组件完成挂载,此时我们可以在监听该状态的useEffect中,用requestAnimationFrame确保DOM完全渲染后再获取尺寸:

import React, { useEffect, useState, useRef } from "react";

const App = () => {
  const [isClicked, setClick] = useState(false);
  const [dimension, setDimension] = useState({ width: 0, height: 0 });
  const ref = useRef(null);

  useEffect(() => {
    if (isClicked && ref.current) {
      const updateSize = () => {
        setDimension({
          width: ref.current.clientWidth,
          height: ref.current.clientHeight,
        });
      };
      // 确保DOM渲染完成后再获取尺寸
      requestAnimationFrame(updateSize);
    }
  }, [isClicked]);

  return (
    <div>
      <button onClick={() => setClick(!isClicked)}>Click me</button>
      {isClicked && (
        <div className="App">
          <div ref={ref} style={{ marginTop: dimension.height }}>
            <h1>Hello</h1>
            <h2>World</h2>
            <h3>!</h3>
          </div>
        </div>
      )}
    </div>
  );
};

export default App;

方案2:用useLayoutEffect替代useEffect(无闪烁优化)

useLayoutEffect会在DOM更新完成后、浏览器重绘前同步执行,能更早获取到DOM尺寸,避免二次渲染的闪烁问题:

import React, { useLayoutEffect, useState, useRef } from "react";

const App = () => {
  const [isClicked, setClick] = useState(false);
  const [dimension, setDimension] = useState({ width: 0, height: 0 });
  const ref = useRef(null);

  useLayoutEffect(() => {
    if (isClicked && ref.current) {
      setDimension({
        width: ref.current.clientWidth,
        height: ref.current.clientHeight,
      });
    }
  }, [isClicked]);

  return (
    <div>
      <button onClick={() => setClick(!isClicked)}>Click me</button>
      {isClicked && (
        <div className="App">
          <div ref={ref} style={{ marginTop: dimension.height }}>
            <h1>Hello</h1>
            <h2>World</h2>
            <h3>!</h3>
          </div>
        </div>
      )}
    </div>
  );
};

export default App;

关键说明

两种方案的核心都是在组件挂载完成后(isClicked变为true时),确保DOM已渲染再获取尺寸,通过更新状态触发二次渲染,让样式正确应用。useLayoutEffect适合对视觉体验要求高的场景,能避免样式闪烁;useEffect配合requestAnimationFrame则更通用,不会阻塞浏览器绘制。

内容的提问来源于stack exchange,提问作者Saltuk Kezer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 10:34:55