ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 왕초보가 작성한 토스 퍼널의 아주 기초적인 사용법
    React 2024. 1. 19. 21:07

    퍼널(Funnel)

    이번 웹잼에서 온보딩 파트를 맡게 되었고, 어떤식으로 구현해야 할지 고민하였는데, 처음에 생각했던 방식은, ‘다음’버튼을 클릭했을 때 navigate로 이동시키는 방법이었다. 하지만 총 6단계로 이루어진 온보딩 파트였고, 공통으로 쓰이는 상태가 있을 것 같다고 판단했다. 이를 위해서 SOPT 웹파트 3주차 리액트 과제를 떠올렸다. 당시 나는 step에 따른 조건부 렌더링 방식을 선택했었고, 많은 props drilling이 발생하긴 했지만 조금 고도화 한다면 충분히 좋은 방법이라 생각했다. 그 즈음 예전에 우리 파트 OB분에게 지나가듯이 들었던 퍼널이 생각나서 검색 후 모든 자료를 뒤져보면서 공부하였다.

    • 왜 이름이 퍼널일까?
      • 퍼널의 뜻은 ‘깔때기’이다.
      • 유저들의 잔존률이 깔때기 처럼, 스텝이 진행될 수록 빠져나가고 남은 유저의 비율이 마치 깔때기 같다고해서 붙여졌다고 한다.
    • 퍼널이란 무엇이며 어떤 상황에 사용하는 것이 좋을까?
      • 퍼널이란 state로 컴포넌트만 갈아끼우는 방식이다.
      • 연속된 form이 많으며, 유저의 연속적인 입력이 많아, 뒤로가기를 누를 필요가 적은 곳에서 사용할 때 좋다고 한다.
      • 전체적인 흐름을 일단 살펴보자
      • 우선 우리 스윗의 퍼널 패턴을 보면,
      우선 constants.ts에 퍼널 스텝의 이름을 상수화 한다.
      
      export const ONBOARDING_FORM_STEP = [
        'NAME',
        'THUMBNAIL',
        'PRESENT',
        'TOURNAMENT_SCHEDULE_REGISTRATION',
        'TOURNAMENT_PROCEEDING',
        'GIFT_ROOM_FIX',
      ] as const;
      
      그 이후 최상위 컴포넌트에서 useFunnel 커스텀 훅을 받아준다.
      OnboardingPage.tsx
      const { Funnel, setStep } = useFunnel(ONBOARDING_FORM_STEP, ONBOARDING_FORM_STEP[0]);
      
      useFunnel.tsx
      
      import { useMemo, useState } from 'react';
      import { NonEmptyArray } from '../types/utility';
      import { Funnel, FunnelProps, Step } from '../components/common/Funnel/Funnel';
      
      export const useFunnel = <Steps extends NonEmptyArray<string>>(
        steps: Steps,
        defaultStep: Steps[number],
      ) => {
        const [step, setStep] = useState<Steps[number]>(defaultStep);
      
        const FunnelComponent = useMemo(
          () =>
            Object.assign(
              (props: Omit<FunnelProps<Steps>, 'step' | 'steps'>) => (
                <Funnel<Steps> step={step} steps={steps} {...props} />
              ),
              { Step },
            ),
          [step],
        );
      
        return { Funnel: FunnelComponent, step, setStep };
      };
      
      벌써부터 머리가 지끈지끈 하다. 타입스크립트의 내장 유틸함수인 Omit은 또 뭐고, 제네릭이 너무 많고… 분명히 좋고 멋있는 코드인 것 같은데 너무 읽기 어렵다.useMemo로 해당 부분만 관리하고 있는 느낌이 들며, 변수명들이 steps, defaultStep인걸 보니 단계별로 스텝을 갈아끼우는 것 같은 느낌이 들었다.
      앞서 말한 useFunnel을 보며 사용법을 알아보자. 
      
      최상위 컴포넌트인 OnboardingPage.tsx
      <Funnel>
              <Funnel.Step name='NAME'>
                <OnBoardingHeader step={1} onClick={handleFirstHistoryClick} />
                {/* step01 */}
                <NameInput
                  onNext={() => setStep(() => 'THUMBNAIL')}
                />
              </Funnel.Step>
              <Funnel.Step name='THUMBNAIL'>
                <OnBoardingHeader step={2} />
      
                {/* step02 */}
                <ThumbnailInput
                  onNext={() => setStep(() => 'PRESENT')}
                />
              </Funnel.Step>
              <Funnel.Step name='PRESENT'>
                <OnBoardingHeader step={3} />
      
                {/* step03 */}
                <GiftDelivery
                  onNext={() => setStep(() => 'TOURNAMENT_SCHEDULE_REGISTRATION')}
                />
              </Funnel.Step>
      
              <Funnel.Step name='TOURNAMENT_SCHEDULE_REGISTRATION'>
                <OnBoardingHeader step={4} />
      
                {/* step04 */}
                <SetTournamentSchedule
                  onNext={() => setStep(() => 'TOURNAMENT_PROCEEDING')}
                />
              </Funnel.Step>
              <Funnel.Step name='TOURNAMENT_PROCEEDING'>
                <OnBoardingHeader step={5} />
      
                {/* step05 */}
                <SetTournamentDuration
                  onNext={() => setStep(() => 'GIFT_ROOM_FIX')}
                />
              </Funnel.Step>
              <Funnel.Step name='GIFT_ROOM_FIX'>
                {/* step06 */}
                <OnboardingFinal />
              </Funnel.Step>
            </Funnel>
      
      퍼널 스텝의 이름을, 좀 전에 constants에서 상수화 시켰던 것들로 1단계 스텝부터 6단계 스텝까지 작성한다.
    • 마지막 퍼널인 GIFT_ROOM_FIX 에서는 마지막이기 때문에 당연히 다음 버튼이 없다.
    • 퍼널을 사용해보니 장점은,사실상 최상위 컴포넌트에서만 상태를 관리해주면 되기 때문에토스의 라이브러리를 더 뜯어보면 좋았겠지만, 우선은 구현을 했다는 것에 만족하며…
    • 데이터의 흐름을 파악하기가 굉장히 쉽고,
    • 상태가 흩어져있지 않게 할 수 있었다.
    • 전체 코드는 토스 홈페이지에 나와있으니 참고해봅시다!
    • 근데 대충봐서도 느낌이, 컴포넌트를 갈아끼우는 코드라는게 느껴지지 않는가?
Designed by Tistory.