전자문서 프로젝트에서는 단순한 PDF 뷰어를 만드는 수준을 넘어,
사용자가 원하는 위치에 컴포넌트를 배치하고 다시 불러올 수 있는 시스템을 구현해야 했습니다.
처음에는 단순해 보였지만, 실제로는 비동기 로딩, 좌표계 변환, 렌더링 타이밍 같은 복잡한 문제가 한꺼번에 몰려왔습니다.
이번 글에서는 제가 겪었던 주요 기술적 어려움과 해결 과정을 공유해보려고 합니다.
처음 겪은 난관은 PDF가 다시 로딩될 때, 컴포넌트가 모두 (0,0) 좌표로 몰려버리는 현상이었습니다.
원인은 onDocumentLoadSuccess 콜백 실행 시점이 PDF 페이지 크기 계산보다 빨랐다는 점이었죠.
const [loadedPages, setLoadedPages] = useState<number[]>([]);
const handlePageLoad = (pageNumber: number) => { setLoadedPages(prev => [...prev, pageNumber]); };
useEffect(() => { if (loadedPages.length === totalPages) { restoreComponents(); // 저장된 좌표에 따라 컴포넌트 재배치 } }, [loadedPages]);
const page = 1
loadedPages 상태로 페이지 로딩을 추적하고, 모든 페이지가 준비된 뒤에만 재배치를 실행하도록 했습니다.
이후 IntersectionObserver를 추가해 DOM 준비 여부까지 체크하니 문제가 말끔히 해결됐습니다.
외부 라이브러리의 생명주기를 이해하고 타이밍을 제어하는 것이 핵심이었습니다.
PDF는 여러 페이지가 세로로 붙어 있기 때문에,
클릭 좌표를 어떤 페이지에 속하는지 정확히 구분하는 게 필요했습니다.
각 페이지 컨테이너에 data-page 속성을 부여
getBoundingClientRect()로 각 페이지의 상대 좌표를 계산
클릭 시 해당 페이지 번호 + 상대 좌표를 함께 저장
const getPdfMousePosition = (e: MouseEvent, pageEl: HTMLElement) => {
const rect = pageEl.getBoundingClientRect();
return {
x: (e.clientX - rect.left) / rect.width,
y: (e.clientY - rect.top) / rect.height,
};
};👉 덕분에 스크롤이나 스케일링이 달라져도,
항상 올바른 위치에 컴포넌트를 표시할 수 있었습니다.
프로젝트 중반, 예상치 못하게 개발 기간이 줄어들면서 모든 기능을 계획대로 담아내기는 어려워졌습니다.
처음에는 부담이 컸지만, 이번 스프린트에서는 핵심 기능에 집중하고 부가 기능은 다음으로 미루는 전략을 선택했습니다.
예를 들어, 컴포넌트 배치와 복원 같은 사용자 경험에 직결되는 기능은 이번에 반드시 포함했고,
부가적인 편의 기능이나 관리 도구는 다음 스프린트로 넘겼습니다.
👉 이 과정을 통해 스프린트 단위에서 범위를 조정하는 감각을 배울 수 있었고,
“모든 걸 다 하려고 하기보다 중요한 것부터 끝내는 것”이 얼마나 중요한지 체감했습니다.
PDF 스케일, 스크롤 위치, 페이지 로딩 상태 등이 얽히면서
위치 계산이 계속 흔들리는 문제가 있었습니다.
scaleStore로 전역 스케일 상태 관리
loadedPages + IntersectionObserver로 모든 페이지 준비 완료 시점 보장
마우스 좌표 계산 함수에서 스케일 반영
const getScaledPosition = (pos: { x: number; y: number }, scale: number) => ({
x: pos.x / scale,
y: pos.y / scale,
});👉 이 과정을 통해 다중 상태(스케일, 스크롤, 로딩) 간 동기화를 경험하며,
UI 아키텍처를 더 단단히 설계하는 방법을 배웠습니다.
돌이켜보면 이 프로젝트는 기술적인 도전이기도 했지만,
그보다 더 큰 배움은 “실무에서 일한다는 게 어떤 의미인지”를 처음 체감한 경험이었습니다.
라이브러리는 도구일 뿐, 원리를 이해해야 한다는 점
일정이 줄어들면 타협이 아니라 우선순위 조정이라는 점
협업은 완벽한 명세보다 꾸준한 소통이 낫다는 점
이는 제게 큰 자산이 되었고, 이후 프로젝트를 대하는 태도에도 큰 영향을 주었습니다.