React 사이드바 토글 시 ECharts 레이아웃 깨짐 해결법 (w.ResizeObserver)

2025. 11. 27. 23:02·개발 일상

상황

최근 회사 프로젝트(react + python)에서 프론트엔드 작업 중 사이드바를 열고 닫을 때 간헐적으로 대시보드 상의 차트 오른쪽에 여백이 생기는 현상을 발견했다.
해당 증상은 간헐적으로 발생하였고, 사이드바의 너비(width)만큼 생긴다는 것을 확인하였다.

증상 분석

  • 사이드바를 열면 메인 화면(차트 포함)이 오른쪽으로 밀림
  • 사이드바를 닫으면 다시 원위치 되어야 함
  • 하지만 간헐적으로 차트의 오른쪽에 여백이 남는 현상 발생
  • 아래 이미지처럼 차트 오른쪽이 padding된 것처럼 비어 있는 증상이 발생함
보안을 위해 이미지의 내용은 masking 처리하였음을 참고

사이드바(좌측 검은 배경)가 활성화 되었을 때의 화면
사이드바가 비활성화 되었을 때의 화면. 우측 차트에 여백이 생김을 확인 가능

원인 분석

프로젝트의 레이아웃 구조는 대략적으로 다음과 같다.

<상위 레이아웃>
  <사이드바 />
  <메인페이지 />   // 이 안에서 CustomECharts 컴포넌트 사용
</상위 레이아웃>

상위 컴포넌트인 layout.tsx에서 사이드바 컴포넌트와 메인페이지(대시보드: 차트 출력) 컴포넌트를 제어하는 형태인데,
사이드바는 햄버거 버튼을 눌러 열고 닫는 구조이며,
닫힐 때는 CSS transition으로 width를 0으로 애니메이션 처리한다.

예를 들면,

.layout-form {
  &.hide {
    .sidebar {
      width: 0px;
      min-width: 0px;
      max-width: 0px;
    }
  }
}

와 같이 css적으로 처리하고 있었다.
즉, 실제로 DOM의 폭이 줄어들지만, 브라우저의 viewport 자체 크기는 변하지 않는다.
이 부분이 문제의 시작점이었다.

메인 페이지(대시보드)에서는 차트 구현을 echarts 라이브러리를 커스텀한 컴포넌트(CustomECharts)로 구현하고 있었는데,
해당 코드 내부에서는 다음과 같이 리사이즈를 처리하고 있었다.

 const chartInstance = useRef(null); // chart 인스턴스를 유지하기 위해 사용

...
window.addEventListener('resize', () => {
  chartInstance.current?.resize();
});

...

코드를 보면 window의 크기가 변할 때만 차트를 다시 그리도록(resize) 되어 있었던 것.

그런데 나의 사이드바의 열림/닫힘 기능은 CSS transition으로 width가 변경되는 구조였고,
이는 브라우저 창 크기가 변하는 게 아니기 때문에 window.resize 이벤트가 아예 발생하지 않는다.
현재 코드 상으로는 브라우저 창 크기 변경만 감지하고, CSS로 인한 DOM 크기 변경은 감지하지 못한 것.

결과적으로 그로 인해 차트는 레이아웃이 바뀐 걸 인식하지 못한 채, 이전 width 상태 그대로 남아 있는 증상이 발생한 것.
간헐적으로 발생한 이유는 사이드의 transition 도중(약0.3초 정도의 이벤트)에 리렌더링이 발생하면서 타이밍에 따라서 정상 작동하거나 버그가 발생한 것이다.

해결 방법: ResizeObserver 도입

이 문제를 해결하기 위해 ResizeObserver API를 사용했다.
이 API는 특정 DOM 요소의 크기 변화를 감지(직접 관찰)할 수 있기 때문에
사이드바 열림/닫힘 시 메인 컨테이너가 미묘하게 변하는 순간에도 반응할 수 있다.
또한, 모든 현대 브라우저에서 지원하는 현대 표준이라는 거...

 const chartInstance = useRef(null); // chart 인스턴스를 유지하기 위해 사용
...

useEffect(() => {
  if (!chartRef.current || !chartInstance.current) return;

  // 1. ResizeObserver로 요소 크기 변화를 감지
  const resizeObserver = new ResizeObserver(() => {
    if (chartInstance.current) {
      chartInstance.current.resize();
    }
  });
  resizeObserver.observe(chartRef.current);

  // 2. window 크기 변경도 병행 지원
  const handleWindowResize = () => {
    chartInstance.current?.resize();
  };
  window.addEventListener('resize', handleWindowResize);

  // 3. 사용한 이벤트 정리(clean-up)
  return () => {
    resizeObserver.disconnect();
    window.removeEventListener('resize', handleWindowResize);
  };
}, [{적절한 의존성 배열}]);

사이드바가 비활성화되어도 차트가 적절하게 resize됨을 확인

 

ResizeObserver란?

ResizeObserver는 브라우저에서 제공하는 DOM 크기 감시 API다.
요소의 width, height가 바뀔 때마다 콜백을 호출해준다.

즉,

* window 전체 크기 변경(resize)
→ window.resize 이벤트로 감지

* 특정 요소의 크기만 변경 (예: 사이드바 width 변화)
→ ResizeObserver로 감지

덕분에 transition 기반 UI에서도 실시간으로 요소의 변경을 인식해 차트를 리사이즈할 수 있다는 거...

참고로, 좀 더 최적화 한다면, requestAnimationFrame을 활용하면 된다고 한다.
ResizeObserver 콜백은 레이아웃 계산 직후 호출되기 때문에,
동일 프레임 안에서 바로 resize()를 호출하면 경고가 뜨거나 깜빡일 수 있다.(동일 프레임 순환 이슈)

이를 방지하려면 다음처럼 한 프레임 늦춰 처리하는 것이 좋다.

const resizeObserver = new ResizeObserver(() => {
  requestAnimationFrame(() => {
    chartInstance.current?.resize();
  });
});

정리: window.resize vs ResizeObserver

구분 방식 감지 대상 사이드바 대응
기존 방식 window.addEventListener('resize') 브라우저 viewport   감지 불가
개선 방식 ResizeObserver 특정 요소의 width/height   대응

 

저작자표시 (새창열림)

'개발 일상' 카테고리의 다른 글

[Critical Issue] React Server Components (RSC) 관련 치명적 보안 취약점 조치법  (0) 2025.12.12
Windows 서버에서 FastAPI 자동 실행 시 발생한 서비스 오류 대응기  (0) 2025.11.11
서로 다른 서버 간 MongoDB 컬렉션 데이터 마이그레이션(ubuntu)  (2) 2025.07.03
[ubuntu 22.04] 최신 chrome 브라우저에서 키보드 입력 문제 해결법  (1) 2025.06.23
YOLO 객체 감지 후 위험 영역 판단 로직 개선기  (1) 2025.06.10
'개발 일상' 카테고리의 다른 글
  • [Critical Issue] React Server Components (RSC) 관련 치명적 보안 취약점 조치법
  • Windows 서버에서 FastAPI 자동 실행 시 발생한 서비스 오류 대응기
  • 서로 다른 서버 간 MongoDB 컬렉션 데이터 마이그레이션(ubuntu)
  • [ubuntu 22.04] 최신 chrome 브라우저에서 키보드 입력 문제 해결법
레실이
레실이
  • 레실이
    레실이의 티스토리
    레실이
  • 전체
    오늘
    어제
    • 분류 전체보기 (91)
      • SE Bootcamp 내용 정리 (63)
      • 알고리즘 연습 (7)
      • Project 주저리 (4)
      • 기술 면접 source (3)
      • 개발 일상 (12)
      • 생성 AI 활용 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    DOM
    자료구조
    state
    인증/보안
    promise
    IT
    react
    fastapi
    MVC
    Ajax
    ubuntu
    Linux
    useState
    CORS
    PickAndDrink
    객체
    JS
    useRef
    비동기
    CSR
    ORM
    Python
    node.js
    node
    문자열
    데이터베이스
    mongoDB
    알고리즘
    CSS
    JavaScript
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
레실이
React 사이드바 토글 시 ECharts 레이아웃 깨짐 해결법 (w.ResizeObserver)
상단으로

티스토리툴바