Skip to content

✔ 도입한 기술(라이브러리)과 이유 (없다면 생략 가능)

  • useSearchParams (react-router-dom)

    → URL 쿼리스트링으로 퍼널 단계를 관리하기 위해 도입했다. 새로고침이나 공유 시에도 현재 단계를 유지할 수 있다.

  • 커스텀 훅 useFunnel

    → 퍼널 단계 관리, 이전/다음 단계 이동, 유효성 검사 등을 재사용 가능한 형태로 분리해 구조화했다.

✔ 문제 요약

퍼널 구조의 온보딩을 구현하면서 다음과 같은 문제가 발생했다:

  1. 온보딩 도중 사용자가 '그룹 매칭'을 선택했을 때, 퍼널 흐름이 갈라지는 구조를 어떻게 설계할지.
  2. 퍼널 단계를 기준으로 프로그레스 바를 표시하려 했으나, 전체 스텝 수가 동적으로 바뀌는 상황에서 진행률을 어떻게 계산할지.
  3. 새로고침 시 현재 단계와 선택값이 유지되지 않아 진행 중이던 온보딩이 초기화되는 UX 문제.
  4. 이미 온보딩을 완료한 사용자가 URL로 다시 접속했을 때 어떻게 처리할지 (재접근 허용? 홈 리디렉션? 에러 페이지?).

✔ 원인 분석

1. 퍼널의 동적 분기 구조

처음에는 하나의 useFunnel 훅 안에서 MATCHING_TYPE에 따라 분기 처리를 하려 했으나,

  • 분기 전에는 전체 스텝의 개수를 알 수 없어 ProgressBar 계산에 문제 발생
  • GROUP_FUNNEL_STEPSFIRST_FUNNEL_STEPS와 구조도 다르고, 쿼리스트링도 별도로 관리되어야 하므로 결국 두 퍼널을 분리

2. 새로고침 시 상태 초기화

  • 상태(state)는 useState로만 관리되고 있었고, URL은 쿼리스트링으로 현재 step만 유지됨
  • 새로고침 시 selections 객체가 초기화되므로, 이전에 선택했던 값들이 모두 사라짐 → 퍼널 흐름상 뒤로 돌아가도 UX가 불안정해짐

3. 완료된 사용자의 재접근

  • API를 통해 서버에 POST 요청을 보낸 후, 사용자가 /onboarding 주소로 다시 접속할 수 있는 구조였음
  • 다시 접속 시 완료된 사용자도 온보딩 흐름으로 진입 가능해 의도치 않은 재요청 또는 중복 입력이 발생할 수 있음

✔ 해결 방법

1. 퍼널 구조 분리 및 navigate 활용

  • MATCHING_TYPE 단계에서 "그룹"을 선택하면 navigate('/onboarding/group?step=GROUP_ROLE')로 이동
  • 일반 온보딩과 그룹 온보딩을 완전히 다른 퍼널 흐름으로 분리하여 useFunnel(GROUP_FUNNEL_STEPS)을 각각 적용
  • goTo를 통해 쿼리스트링만 변경하며 단계 이동 → 새로고침 후에도 해당 단계 유지 가능

2. ProgressBar와 동적 스텝 수 처리

  • 일반 퍼널에서는 ProgressBar currentStep={progressOverride ?? currentIndex}로 계산
  • 그룹 퍼널로 분기된 이후에는 GROUP_FUNNEL_STEPS.length를 기준으로 별도로 ProgressBar 렌더링
  • progressOverride state를 통해 조건부로 오버라이딩 가능하게 구현

3. 새로고침 시 단계 유지 및 에러 방지

  • useFunnel 내부에서 쿼리스트링(?step=X)이 없거나 유효하지 않을 경우,

    setSearchParams({ step: steps[0] })으로 강제 초기화

    → 잘못된 접근은 navigate(ROUTES.ERROR)로 에러 페이지 유도

tsx
useEffect(() => {
  if (!stepFromUrl) {
    setSearchParams({ step: steps[0] }, { replace: true });
  }
  if (!isValidStep) {
    navigate(ROUTES.ERROR, { replace: true });
  }
}, [...]);

4. 완료된 사용자의 재접근 처리

  • 서버에서 이미 온보딩을 완료한 사용자의 경우 /onboarding 접속 시 홈으로 redirect 되도록 가드 필요
  • 클라이언트에서 GET /my/onboarding-status와 같은 API를 통해 진행 여부 판단 → 진입 제한하거나 중간단계에서 redirect 처리

✔ 회고 및 개선 방향

  • 퍼널 UI는 정적인 흐름을 가정하면 안 될 것 같다.

    특히 UX 흐름 상 사용자의 선택에 따라 다음 단계가 달라지는 경우가 많기 때문에,

    퍼널 전체 단계를 하나의 고정된 리스트로 처리하기보다 분기별 퍼널을 나누고 구조적으로 분리하는 게 안정적이었다.

  • ProgressBar 계산은 퍼널 흐름에 강하게 의존한다.

    ‘전체 단계 수를 어디까지 계산할 것인가’라는 문제는 분기를 포함하면 더 복잡해지므로,

    분기된 퍼널 흐름마다 고유한 useFunnel을 관리하고 progressOverride 등을 활용하는 전략이 효과적이었다.

  • URL 기반 상태 관리의 장점

    useSearchParams를 통해 퍼널 단계를 URL에 명시한 덕분에, 새로고침/뒤로가기/직접 접근 등의 시나리오에서도 상태를 안정적으로 유지할 수 있었다.

  • 상태 유지와 초기화의 균형 필요

    selections를 로컬스토리지에 저장할지 여부는 아직 보류했지만, 초기에는 완전히 사라지는 UX가 너무 불친절해서 추후에는 step만 유지하고 값은 임시적으로 sessionStorage에 저장하는 방안을 고려할 수 있을 듯하다.

  • 중복 접근 방지 필요

    이미 완료된 사용자의 /onboarding 재접근 이슈는 아직 명확한 UX 기준이 없다면 서버에서 진입 제한 flag를 내려주는 구조로 처리하는 것이 안전할 것 같다.