인턴

[ Troubleshooting🛠️ ] 모달 표시 문제 해결

choijming21 2025. 4. 29. 18:44

1.  문제 발생❓

  • be, fe, ai 세 개의 페이지 설명회 모달 작업 중
    • 세 페이지 모두 remoteConfig 또는 orientation 값이 null일 경우 모달이 표시되지 않도록 조건부 렌더링을 설정했습니다.
    • be, fe 페이지는 필요한 데이터(remoteConfig, orientation)를 정상적으로 받아와 설명회 모달이 표시됩니다.
    • ai 페이지는 현재 설명회가 없어 관련 데이터가 전달되지 않으므로, 모달이 표시되지 않는 것이 의도한 동작입니다.
  • ai 페이지에서는 예상대로 모달이 표시되지 않았지만, aibe 또는 aife로 페이지 전환 시 모달이 정상적인 위치에서 나타나지 않고 즉시 표시되는 현상이 발생했습니다.
  • 이 과정에서 세 페이지의 팝업 상태를 하나의 아톰(atom)으로 관리하고 있다는 구조적 문제도 발견했습니다. + 다음 블로그에서 작성!

 

 

 

2.  원인 추론 🔎

  • AI 페이지에서는 remoteDataorientationDatanull이기 때문에 모달이 표시되지 않는 것이 정상적인 동작!
  • 그래서 콘솔로 isAlreadyPopup 상태값을 확인해보니 AI 페이지에서도 이 값이 true로 변경되는 현상을 발견했습니다.
    • isAlreadyModal은 모달이 사용자에게 한 번 표시되었는지(true) 또는 **아직 표시되지 않았는지(false)**를 관리하는 상태값입니다.
    • AI 페이지에서는 실제로 모달이 화면에 표시되지 않았음에도 불구하고 isAlreadyModal 값이 true로 변경되고 있었습니다.
    • 이로 인해 AI 페이지에서 BE/FE 페이지로 이동했을 때, 시스템은 이미 모달이 표시되었다고 판단하여 정상적인 모달 표시 로직이 실행되지 않는 문제가 발생했습니다.
  • ai 페이지에서는 모달이 뜨지 않으니 isAlreadyModal이 true 값으로 변경되면 절대 안됨 => 이것을 해결해야 함!
const { remoteData, orientationData } = useOrientationBanner(
    COURSE_DETAIL[course].koreanName,
  );

  const [modal, setModal] = useAtom(orientationModalAtom);
  const scrollY = useWindowScrollY();
  const [isAlreadyModal, setIsAlreadyModal] = useAtom(isAlreadyModalAtom);

  useScrollToTriggerModal({
    scrollY,
    reachingDiv,
    isAlreadyModal,
    setModal,
    setIsAlreadyModal,
  });

  if (isNil(remoteData) || isNil(orientationData)) {
    return null;
}

return // 해당 모달 디브

 

 

 

 

 

 

 

3.  해결 과정 📋

1. 호출 순서를 바꿔봄 

: 초기에 데이터가 없으면 return null을 해 커스텀 훅이 실행되지 않게 해봄

javascript
if (isNil(remoteData) || isNil(orientationData)) {
  console.log('remoteData 또는 orientationData이 null이므로 컴포넌트 반환하지 않음');
  return null;
}

useScrollToTriggerModal({
  scrollY,
  reachingDiv,
  isAlreadyModal,
  setModal,
  setIsAlreadyModal,
});
  • React Hooks 규칙 위반: 조건부(if문 이후)로 훅을 호출하고 있음
  • ESLint 에러: React Hook "useScrollToTriggerModal" is called conditionally. React Hooks must be called in the exact same order in every component render.

 

2. useScrollToTriggerModal 훅 분석

: 이 함수를 호출하는 부분을 살펴보면 커스텀 훅 밑에 if 조건문이 있으니 데이터가 없어도 커스텀 훅을 실행될 것입니다.

 useScrollToTriggerModal({
    scrollY,
    reachingDiv,
    isAlreadyModal,
    setModal,
    setIsAlreadyModal,
  });

  if (isNil(remoteData) || isNil(orientationData)) {
    return null;

 

 

그래서 커스텀 훅을 살펴보았습니다:

  • showModal 파라미터가 기본값 true로 설정되어 있었습니다.
  • 이로 인해 첫 번째 조건에서 안걸리기 때문에 로직이 실행되었습니다.
  • 로직 실행 결과 => setIsAlreadyModal이 true값으로 바뀜
javascript
function useScrollToTriggerModal({
  scrollY,
  reachingDiv,
  isAlreadyModal,
  setModal,
  setIsAlreadyModal,
  showModal = true,
}: UseScrollToTriggerModalProps) {
  useEffect(() => {
    const innerHeight = window.innerHeight;
    if (!reachingDiv || isAlreadyModal || !showModal) {
      return;
    }
    if (!isAlreadyModal && scrollY + innerHeight >= reachingDiv) {
      setModal(true);
      setIsAlreadyModal(true);
    }
  }, [scrollY, reachingDiv]);
}

 

 

그래서 이 ai 페이지에서는 로직이 실행되면 안되니깐

  • 커스텀 함수 호출 부분에서 showModal에 조건문을 걸어주었습니다.
useScrollToTriggerModal({
  scrollY,
  reachingDiv,
  isAlreadyModal,
  setModal,
  setIsAlreadyModal,
  showModal: !isNil(remoteData) && !isNil(orientationData)),// 핵심 수정
});

if (isNil(remoteData) || isNil(orientationData)) {
  return null;
}

 

 

초기에 showModal 파라미터를 활용하여 데이터가 없을 때 로직이 실행되지 않도록 설정

  • 데이터가 없을 시 false값으로 내려와 첫 번째 조건에서 걸리게 되어 isAlreadyPopup이 true값으로 변경되지 않을 것입니다!!
  • 이로 인해 AI 페이지에서는 isAlreadyModal 상태가 변경되지 않아, 페이지 전환 시 모달이 예기치 않게 표시되는 문제를 해결했습니다.
function useScrollToTriggerModal({
  scrollY,
  reachingDiv,
  isAlreadyModal,
  setModal,
  setIsAlreadyModal,
  showModal = true,
}: UseScrollToTriggerModalProps) {
  useEffect(() => {
    const innerHeight = window.innerHeight;
    if (!reachingDiv || isAlreadyModal || !showModal) {
      return;
    }
    if (!isAlreadyModal && scrollY + innerHeight >= reachingDiv) {
      setModal(true);
      setIsAlreadyModal(true);
    }
  }, [scrollY, reachingDiv]);
}

 

 

                               

 

4.  결론 💬

  • React Hook는 항상 조건문 이전에 호출해야 합니다.
  • 디버깅 시 콘솔로그를 전략적으로 배치하여 데이터 상태 변화를 추적하는 것이 중요합니다!