如何在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
相关产品推荐
相关产品推荐

