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

React嵌套可展开容器组件状态不一致问题求助

问题分析与解决方案

问题根源

  1. 依赖数组触发时机错误:父容器的useEffect仅监听expanded和children,但子容器展开/关闭时,父组件的children引用并未改变(子组件实例未更换,仅内部状态变化),导致父容器不会重新计算高度。
  2. 高度计算时机偏差:子容器状态变化时,父容器无法实时感知内容高度变化;偶尔触发计算时,DOM可能未完成更新,导致获取到错误的高度值。

修复方案:使用ResizeObserver监听内容高度变化

通过ResizeObserver可以实时监听容器内容的高度变化,不管是自身展开状态改变,还是子容器高度变化,都能自动更新父容器的maxHeight。

修改后的组件代码:

import { useRef, useState, useEffect } from 'react';

export default function ExpandableContainer({ expanded, children }) {
  const containerRef = useRef(null);
  const contentRef = useRef(null);
  const [style, setStyle] = useState({ maxHeight: 0 });

  // 处理自身展开/收起的初始高度设置
  useEffect(() => {
    if (expanded) {
      const height = contentRef.current.getBoundingClientRect().height;
      setStyle({ maxHeight: height });
    } else {
      setStyle({ maxHeight: 0 });
    }
  }, [expanded]);

  // 监听内容高度变化,实时更新maxHeight
  useEffect(() => {
    if (!expanded || !contentRef.current) return;

    const resizeObserver = new ResizeObserver((entries) => {
      entries.forEach(entry => {
        const height = entry.contentRect.height;
        setStyle({ maxHeight: height });
      });
    });

    resizeObserver.observe(contentRef.current);
    return () => resizeObserver.disconnect();
  }, [expanded]);

  return (
    <div ref={containerRef} style={style} className='xxx'>
      <div ref={contentRef}>
        {children}
      </div>
    </div>
  );
}

方案说明

  • 拆分两个useEffect:一个处理自身expanded状态切换时的初始高度设置,另一个在展开状态下监听内容高度变化。
  • 直接给内部内容容器绑定ref,避免依赖DOM层级(原代码中ref.current.children[0]易受结构变更影响)。
  • ResizeObserver会自动捕捉子容器展开/关闭带来的高度变化,实时更新父容器的maxHeight,完全适配嵌套场景的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 05:35:18