문서보기
@toss/use-funnel 마이그레이션

@toss/use-funnel 마이그레이션

이 문서는 @toss/use-funnel (opens in a new tab) 에서 사용하던 코드를 새로운 @use-funnel 로 마이그레이션하는 방법을 설명합니다. @toss/use-funnel 은 Next.js Page Router 로 작성되어서 이 문서는 @use-funnel/next 로 마이그레이션 하는 방법을 설명합니다.

새로운 혜택

  • 상태가 히스토리를 따라가지 않는 이슈를 수정했어요(관련 문서 (opens in a new tab))
  • 단계별로 상태를 만들 수 있게 되었어요.
  • Next.js 외에 react-router, @react-navigation/native 를 지원해요.

설치하기

설치하기 (opens in a new tab)에서 더 자세한 내용을 확인해보세요.

npm install @use-funnel/next --save

Breaking Change

steps 마이그레이션

새로운 @use-funnel 에서는 단순히 단계만 정의할 수 있는게 아니라 단계별로 상태를 정의할 수 있습니다. @toss/use-funnel 으로 작성된 퍼널에서 이러한 타입이 필요없거나, 상태가 있더라도 단계별로 다른게 필요없다면 @use-funnel 에서 제공하는 createStepBuilder() 를 활용할 수 있습니다.

Before

import { useFunnel } from '@toss/use-funnel';
 
const FUNNEL_STEPS = ['A', 'B', 'C'] as const;
const [Funnel, setFunnel] = useFunnel(FUNNEL_STEPS);
 

After

import { createFunnelSteps } from '@use-funnel/next';
 
const steps = createFunnelSteps()
  .extends(['A', 'B', 'C'])
  .build();
 
const funnel = useFunnel({
  steps,
  initial: {
    step: 'A',
    context: {}
  }
});

<Funnel />, <Funnel.Step /> 컴포넌트 마이그레이션

새로운 @use-funnel 에서는 단계별로 상태 타입을 추론하기 위해 별도의 컴포넌트를 사용하지 않고 useFunnel() 에서 반환되는 funnel.step, funnel.context 를 통해 현재 단계와 상태를 확인할 수 있습니다. funnel.step 을 switch-case 문으로 구별하여 렌더링할 수 있습니다.

Before

import { useFunnel } from '@toss/use-funnel';
 
const [Funnel, setFunnel] = useFunnel([
  'A', 'B'
] as const);
 
return (
  <Funnel>
    <Funnel.Step name="A">
      <div>A</div>
    </Funnel.Step>
    <Funnel.Step name="B">
      <div>B</div>
    </Funnel.Step>
  </Funnel>
)

After

import {useFunnel} from '@use-funnel/next';
 
const steps = createFunnelSteps().extends(['A', 'B']).build();
const funnel = useFunnel({
  steps,
  initial: {
    step: 'A',
    context: {}
  }
});
 
switch (funnel.step) {
  case 'A':
    return <div>A</div>;
  case 'B':
    return <div>B</div>;
}
 

또는 <funnel.Render /> 컴포넌트를 통해 더욱 더 선언적으로 구현할 수 있습니다. 자세한 내용은 funnel.Render 컴포넌트 문서를 참고해주세요.

withState() 마이그레이션

@toss/use-funnelwithState() 를 통해 상태를 구현하고 있었다면 createFunnelSteps() 에 제네릭을 넘겨서 이를 구현할 수 있습니다.

Before

import { useFunnel } from '@toss/use-funnel';
 
const [Funnel, state, setState] = useFunnel([
  'A', 'B', 'C'
] as const).withState<{
  foo?: string;
  bar?: number;
}>({
  foo: 'Hello',
  bar: 5
});

After

import { useFunnel, createFunnelSteps } from '@use-funnel/next';
 
const steps = createFunnelSteps<{
  foo?: string;
  bar?: number;
}>()
  .extends(['A', 'B', 'C'])
  .build();
 
const funnel = useFunnel({
  steps,
  initial: {
    step: 'A',
    context: {
      foo: 'Hello',
      bar: 5,
    },
  },
});

stepQueryKey 진입 마이그레이션

@toss/use-funnel 에서는 stepQueryKey 의 기본값으로 “funnel-step” 이라는 값을 사용하고 있습니다. 새로운 @use-funnel 에서는 내부적으로 키를 생성하여 관리하기 때문에 이를 진입점으로 사용하고 있었다면 직접 해당 query parameter를 initial 에 넘겨주어야 합니다.

Before

import { useFunnel } from '@toss/use-funnel';
 
// 퍼널 페이지로 이동하되, B Step으로 시작
router.push('/funnel?my-funnel-step=B');
 
// B Step으로 시작
const [Funnel, setFunnel] = useFunnel([
  'A', 'B', 'C'
] as const, {
  stepQueryKey: 'my-funnel-step'
});
 

After

import { useRouter } from 'next/router';
import { useFunnel, createFunnelSteps } from '@use-funnel/next';
 
// 퍼널 페이지로 이동하되, B Step으로 시작
router.push('/funnel?my-funnel-step=B');
 
const router = useRouter();
const initialStep = router.query['my-funnel-step'];
const steps = createFunnelSteps().extends(['A', 'B', 'C']).build();
 
// B Step으로 시작
const funnel = useFunnel({
  steps,
  initial: {
    step: intialStep as keyof typeof steps,
    context: {}
  }
});

onStepChange 마이그레이션

새로운 @use-funnel 에서는 현재 단계가 무엇인지 제공하고 있습니다. 이를 활용하여 useEffect() 에서 활용할 수 있습니다.

Before

import { useFunnel } from '@toss/use-funnel';
 
const [Funnel, setFunnel] = useFunnel([
  'A', 'B', 'C'
] as const, {
  onStepChange(step) {
    console.log(`CURRENT STEP: ${step}`);
  }
});
 

After

import { useEffect } from 'react';
import { useFunnel, createFunnelSteps } from '@use-funnel/next';
 
const steps = createFunnelSteps()
  .extends(['A', 'B', 'C'])
  .build();
 
const funnel = useFunnel({
  steps,
  initial: {
    step: 'A',
    context: {}
  }
});
 
useEffect(() => {
  console.log(`CURRENT STEP: ${funnel.step}`);
}, [funnel.step]);