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

如何在React父组件中使用子组件的动态高度值

解决React Remix中Child组件高度传递给Parent的可行方案

方案1:状态提升(推荐,最简洁直接)

这是React组件间共享状态的标准做法,你之前可能没处理好height的监听逻辑,具体实现如下:

Parent组件代码

import { useState } from 'react';
import Child1 from './Child1';
import Child2 from './Child2';
import Child3 from './Child3';

export default function Parent() {
  // 定义存储Child2中div1高度的状态
  const [child2Div1Height, setChild2Div1Height] = useState(0);

  // 给Child1和Child3生成条件样式类名
  const getChildConditionalClass = () => {
    return child2Div1Height > 300 ? 'some-large-style' : 'some-normal-style';
  };

  return (
    <div className="parent-container">
      <Child1 className={getChildConditionalClass()} />
      <Child2 onHeightChange={setChild2Div1Height} />
      <Child3 className={getChildConditionalClass()} />
    </div>
  );
}

Child2组件代码

import { useEffect } from 'react';
import useElementSize from './useElementSize'; // 替换为你的Hook实际路径

export default function Child2({ onHeightChange }) {
  const [squareRef, { height }] = useElementSize();

  // 监听height变化,实时同步给父组件
  useEffect(() => {
    if (typeof height === 'number' && height > 0) {
      onHeightChange(height);
    }
  }, [height, onHeightChange]);

  return (
    <section className="flex flex-col w-full">
      <p className="mx-auto text-5xl font-bold">{height}</p>
      <div className="w-full bg-black" ref={squareRef}>
        {/* div1的内容 */}
      </div>
      {/* div2的内容 */}
    </section>
  );
}

核心逻辑:把状态放在需要使用它的最顶层组件(Parent),通过props传递更新函数给Child2,当Child2的高度变化时,调用更新函数同步状态,再用这个状态给Child1/Child3设置样式。


方案2:useImperativeHandle(适合主动获取高度的场景)

如果需要Parent主动触发获取Child2的高度(比如按钮点击后),可以用这个方法:

Parent组件代码

import { useRef, useState, useEffect } from 'react';
import Child1 from './Child1';
import Child2 from './Child2';
import Child3 from './Child3';

export default function Parent() {
  const child2Ref = useRef(null);
  const [child2Div1Height, setChild2Div1Height] = useState(0);

  // 组件挂载后主动获取一次高度
  useEffect(() => {
    if (child2Ref.current) {
      const height = child2Ref.current.getDiv1Height();
      setChild2Div1Height(height);
    }
  }, []);

  const getChildConditionalClass = () => {
    return child2Div1Height > 300 ? 'some-large-style' : 'some-normal-style';
  };

  return (
    <div className="parent-container">
      <Child1 className={getChildConditionalClass()} />
      <Child2 ref={child2Ref} />
      <Child3 className={getChildConditionalClass()} />
      {/* 点击按钮手动刷新高度 */}
      <button onClick={() => {
        const height = child2Ref.current?.getDiv1Height();
        setChild2Div1Height(height);
      }}>刷新高度</button>
    </div>
  );
}

Child2组件代码

import { useImperativeHandle, forwardRef } from 'react';
import useElementSize from './useElementSize';

// 必须用forwardRef包裹才能接收父组件传的ref
const Child2 = forwardRef((props, ref) => {
  const [squareRef, { height }] = useElementSize();

  // 暴露给父组件的方法
  useImperativeHandle(ref, () => ({
    getDiv1Height: () => height
  }), [height]); // 依赖height,确保返回最新值

  return (
    <section className="flex flex-col w-full">
      <p className="mx-auto text-5xl font-bold">{height}</p>
      <div className="w-full bg-black" ref={squareRef}>
        {/* div1的内容 */}
      </div>
      {/* div2的内容 */}
    </section>
  );
});

export default Child2;

方案3:Context(适合多层组件传递,避免props drilling)

如果组件层级更深,Child1/Child3不是直接在Parent下,用Context可以避免层层传递props:

先创建HeightContext.js

import { createContext, useContext, useState } from 'react';

const HeightContext = createContext({
  child2Div1Height: 0,
  setChild2Div1Height: () => {}
});

export function HeightProvider({ children }) {
  const [child2Div1Height, setChild2Div1Height] = useState(0);
  return (
    <HeightContext.Provider value={{ child2Div1Height, setChild2Div1Height }}>
      {children}
    </HeightContext.Provider>
  );
}

export function useHeightContext() {
  return useContext(HeightContext);
}

Parent组件代码

import { HeightProvider } from './HeightContext';
import Child1 from './Child1';
import Child2 from './Child2';
import Child3 from './Child3';

export default function Parent() {
  return (
    <HeightProvider>
      <div className="parent-container">
        <Child1 />
        <Child2 />
        <Child3 />
      </div>
    </HeightProvider>
  );
}

Child2组件代码

import { useEffect } from 'react';
import useElementSize from './useElementSize';
import { useHeightContext } from './HeightContext';

export default function Child2() {
  const [squareRef, { height }] = useElementSize();
  const { setChild2Div1Height } = useHeightContext();

  useEffect(() => {
    if (typeof height === 'number' && height > 0) {
      setChild2Div1Height(height);
    }
  }, [height, setChild2Div1Height]);

  return (
    <section className="flex flex-col w-full">
      <p className="mx-auto text-5xl font-bold">{height}</p>
      <div className="w-full bg-black" ref={squareRef}>
        {/* div1的内容 */}
      </div>
      {/* div2的内容 */}
    </section>
  );
}

Child1组件代码(Child3同理)

import { useHeightContext } from './HeightContext';

export default function Child1() {
  const { child2Div1Height } = useHeightContext();
  const conditionalClass = child2Div1Height > 300 ? 'some-large-style' : 'some-normal-style';

  return <div className={`child1 ${conditionalClass}`}>Child1内容</div>;
}

选择建议

  • 如果只是Parent直接使用Child2的高度,优先用方案1(状态提升),代码最少最直观,无额外复杂度。
  • 如果需要Parent主动控制获取高度的时机,用方案2。
  • 如果组件层级深,props传递麻烦,用方案3。

内容的提问来源于stack exchange,提问作者Dujveq E

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 02:40:41