이미지 갤러리에서 사진을 넘길 때 줌 상태가 유지되면 사용자 경험에 혼란을 줄 수 있습니다. 이전 이미지에서 확대한 상태로 다음 이미지로 넘어가면, 새 이미지의 동일한 부분(위치)이 확대되어 보이게 되는데, 이는 사용자가 원하는 결과가 아닐 수 있습니다. 이 글에서는 React에서 react-zoom-pan-pinch 라이브러리를 사용하여 이미지 전환 시 줌 상태를 효과적으로 초기화하는 방법을 소개합니다.

문제 상황

이미지 갤러리에서 다음과 같은 문제가 발생할 수 있습니다:

  1. 사용자가 이미지를 확대한 상태에서 다음 이미지로 넘어갈 때 줌 레벨이 유지됨
  2. 이미지 전환 시 확대된 상태로 인해 새로운 이미지의 중요한 부분이 보이지 않을 수 있음
  3. 일관된 사용자 경험을 위해 각 이미지는 처음 보여질 때 항상 전체 이미지가 보이는 상태여야 함

실패한 해결 방법 : key 속성을 활용한 줌 상태 초기화

초기화가 이루어 지나 컴포넌트가 다시 생성되며 마운트 되기 때문에 사진 전환시에 딜레이가 생겨 중간중간 빈 화면이 보이는 문제가 발생했습니다. 이는 사용자에게 불편을 줄 수 있어 다른 방법을 사용하기로 결정했습니다.

해결 방법: useRef와 useEffect를 활용한 줌 상태 초기화

react-zoom-pan-pinch 라이브러리를 사용할 때, 이미지가 변경될 때마다 줌 상태를 초기화하는 가장 효과적인 방법은 다음과 같습니다:

import { memo, useEffect, useRef } from "react";
import { ReactZoomPanPinchRef, TransformWrapper } from "react-zoom-pan-pinch";
import { ImageData } from "../../api/imageApi";
import ZoomControls from "./ZoomControls";
import ImageRenderer from "./ImageRenderer ";

interface TransformViwerProps {
  currentImageSrcMetadata?: ImageData;
  isLoaded: boolean;
}

const TransformViwer = ({
  currentImageSrcMetadata = {
    id: 0,
    src: "",
    alt: "",
  },
}: TransformViwerProps) => {
  // TransformWrapper의 메서드에 접근하기 위한 ref 생성
  const transformRef = useRef<ReactZoomPanPinchRef | null>(null);

  // 이미지 ID가 변경될 때마다 줌 상태 초기화
  useEffect(() => {
    if (transformRef.current && transformRef.current.resetTransform) {
      // 애니메이션 없이 빠르게 리셋
      transformRef.current.resetTransform(0);
    }
  }, [currentImageSrcMetadata.id]); // 이미지 ID가 변경될 때만 실행

  return (
    <TransformWrapper
      initialScale={1}
      initialPositionX={0}
      initialPositionY={0}
      disablePadding={true}
      onInit={(ref) => {
        // 컴포넌트 초기화 시 ref 저장
        transformRef.current = ref;
      }}
    >
      {({ zoomIn, zoomOut, resetTransform }) => (
        <div className="absolute inset-0 w-full h-full">
          <ZoomControls
            zoomIn={zoomIn}
            zoomOut={zoomOut}
            resetTransform={resetTransform}
          />
          <ImageRenderer imageMetadata={currentImageSrcMetadata} />
        </div>
      )}
    </TransformWrapper>
  );
};

// 메모이제이션으로 불필요한 리렌더링 방지
export default memo(TransformViwer);

구현 방법 상세 설명

1. useRef로 TransformWrapper 인스턴스 참조하기

const transformRef = useRef<ReactZoomPanPinchRef | null>(null);

useRef 훅을 사용하여 TransformWrapper 컴포넌트의 메서드에 접근할 수 있는 참조를 생성합니다. 이 참조를 통해 줌 상태를 제어할 수 있습니다.

2. onInit 콜백으로 참조 저장하기

onInit={(ref) => {
  transformRef.current = ref;
}}

TransformWrapperonInit 콜백은 컴포넌트가 마운트될 때 호출됩니다. 이 시점에 제공되는 ref 객체를 통해 zoomIn, zoomOut, resetTransform 등의 메서드에 접근할 수 있습니다. 우리는 이 reftransformRef.current에 저장합니다.

3. useEffect로 이미지 변경 감지 및 줌 상태 초기화

useEffect(() => {
  if (transformRef.current && transformRef.current.resetTransform) {
    // 애니메이션 없이 빠르게 리셋
    transformRef.current.resetTransform(0);
  }
}, [currentImageSrcMetadata.id]);

useEffect 훅을 사용하여 currentImageSrcMetadata.id가 변경될 때마다 줌 상태를 초기화합니다. 파라미터 0은 애니메이션 지속 시간(밀리초)으로, 0으로 설정하면 즉시 초기화됩니다. 이는 이미지 전환 시 깜빡임을 최소화하기 위한 설정입니다.

4. memo로 불필요한 리렌더링 방지

export default memo(TransformViwer);

memo를 사용하여 컴포넌트를 메모이제이션함으로써 props가 변경되지 않았을 때 불필요한 리렌더링을 방지합니다. 이는 성능 최적화에 중요합니다

결론

react-zoom-pan-pinch 라이브러리의 공식 홈페이지를 들어가 탐색하며 원하는 기능을 구현할 수 있었습니다.

깜빡임도 없고 사진 전환시에 전체 모습을 볼 수 있게 하여 사용자의 편의성을 증진시켰습니다.

'개발 > 기록' 카테고리의 다른 글

React JSX에서의 0 처리 특징  (0) 2025.03.26
zoom & swipe image Viewer: zoom, reset 에러 해결  (0) 2025.03.25
제네릭 타입 선언시 nerver와 void의 차이  (0) 2025.03.01
유용한 css  (0) 2025.02.24
nextjs 쿠키 설정 의문  (0) 2025.02.24

+ Recent posts