본문 바로가기
React/React 실습

[React] Material-UI Popover 위치 보정과 애니메이션 적용 시행착오 기록

by haheehee 2025. 3. 14.
728x90

 

이번 글에서는 Material-UI의 Popover 컴포넌트 사용 중 겪었던 시행착오와, 위치 보정 및 자연스러운 애니메이션을 적용하기까지의 해결 과정을 기록합니다.

1. 문제 상황

처음에는 Material-UI의 Popover를 사용하여 특정 버튼을 클릭하면 팝업이 열리도록 구현하였습니다. 하지만 팝업 내부의 내용이 확장될 때 다음과 같은 문제가 발생했습니다.

  • 내용이 확장되면 Popover가 화면 밖으로 벗어나는 현상
  • Popover 위치가 자동으로 보정되지 않아 부자연스러운 UI
  • 위치 보정이 되어도 움직임이 너무 딱딱해서 UX가 나쁨

2. 처음 시도한 방법 (실패)

처음에는 Popover를 Popper로 변경하여 popperRef를 사용해 위치를 직접 업데이트하려고 했습니다.

<Popper
    open={open}
    anchorEl={anchorEl}
    placement="bottom-start"
    popperRef={popperRef}
  >
    {/* 내용 */}
  </Popper>

문제점:

  • 기존 Popover에서 잘 동작하던 ClickAwayListener나 자동 위치 보정 기능이 제대로 동작하지 않음.
  • 키보드 이벤트나 focus 문제가 발생하여 복잡도가 증가함.

3. 두 번째 시도 (실패)

Popover를 유지하면서 내용이 확장된 후 popperRef.current.update()를 사용해 보정을 시도했지만, Popover에서는 popperRef를 지원하지 않아 TypeScript 오류가 발생했습니다.

4. 최종 해결 방법

결국 Popover를 유지하면서, 내용이 확장된 직후 window.dispatchEvent(new Event('resize'))를 호출하여 위치 보정을 유도하고, 보정 시 transition 효과를 주어 부드럽게 처리하는 방법을 사용했습니다.

코드 예제

import React, { useState } from 'react';
import Popover from '@mui/material/Popover';
import Button from '@mui/material/Button';

function MyPopover({ setAdobeFile }) {
  const [anchorEl, setAnchorEl] = useState(null);
  const [expanded, setExpanded] = useState(false);

  const handleOpen = (event) => {
    setAnchorEl(event.currentTarget);
  };

  const handleClose = () => {
    setAnchorEl(null);
    if (setAdobeFile) {
      setAdobeFile(null);
    }
  };

  const handleExpand = () => {
    setExpanded(true);
    // 내용 확장 후 resize 이벤트 발생 → 위치 재계산 유도
    window.dispatchEvent(new Event('resize'));
  };

  const open = Boolean(anchorEl);

  return (
    <div>
      <Button onClick={handleOpen}>열기</Button>
      <Popover
        open={open}
        anchorEl={anchorEl}
        onClose={handleClose}
        marginThreshold={16}
        anchorOrigin={{
          vertical: 'bottom',
          horizontal: 'left',
        }}
        PaperProps={{
          style: {
            transition: 'transform 0.3s ease-in-out' // 위치 이동 애니메이션 효과
          }
        }}
      >
        <div style={{ width: 200, height: expanded ? 300 : 100, padding: 16 }}>
          내용 영역
          {!expanded && (
            <Button onClick={handleExpand}>확장하기</Button>
          )}
        </div>
      </Popover>
    </div>
  );
}

export default MyPopover;

주요 포인트

  • 자동 위치 보정: 내용이 확장된 후 window.dispatchEvent(new Event('resize'))를 호출하여 Popover 내부의 Popper.js가 위치를 재계산하도록 유도했습니다.
  • 부드러운 애니메이션 효과: PopoverPaperProps를 통해 transition: 'transform 0.3s ease-in-out'을 적용하여, 위치가 재조정될 때 자연스럽게 이동하도록 처리했습니다.

5. 시행착오에서 얻은 교훈

  • Material-UI의 Popover는 Popper.js를 내부적으로 사용하지만, 직접 업데이트를 컨트롤하기 어렵다.
  • 브라우저의 resize 이벤트는 Popper.js가 위치를 재계산하도록 유도하는 유용한 트릭이다.
  • 애니메이션 효과를 위해서는 Popover의 PaperPropstransform 관련 CSS를 적용하는 것이 가장 자연스럽다.

6. 마무리

Popover에서 발생하는 위치 보정 문제를 해결하기 위해 여러 가지 방법을 시도했지만, 결국 가장 단순하면서도 확실한 방법은 resize 이벤트를 활용하는 것이었습니다. 그리고 transition 효과를 적용하여 UX를 개선할 수 있었습니다.

앞으로도 비슷한 UI 문제를 겪게 된다면, 이러한 경험이 도움이 되길 바랍니다.

728x90

댓글