회원가입 페이지 같은 경우, 여러 단계들로 이루어져 있다. 이러한 구조를 퍼널 패턴이라 한다. 주로 마케팅 분야에서 많이 사용되며, 구매 과정에서 고객이 거치는 여러 단계를 설명할 대 사용되는 용어이다.
만약, 퍼널의 각 단계에 대한 상태를 query string으로 관리한다고 했을 경우 코드는 아래와 같다.
export function JoinPage(){
const searchParams = useSearchParams();
const step = searchParams.get('step');
return(
<main>
{step === '1' && <JoinStep1 />}
{step === '2' && <JoinStep2 />}
</main>
)
}
// ..
export function JoinStep1(){
const router = useRouter();
const handlePrev = (data) => {
router.push('/login')
}
const handleSubmit = (data) => {
await submit(data);
router.push('/join?step=2')
}
// ..
}
// ..
export function JoinStep2(){
const router = useRouter();
const handlePrev = (data) => {
router.push('/join?step=1')
}
const handleSubmit = (data) => {
await submit(data);
router.push('/join?step=3')
}
// ..
}
단계가 늘어나면, 코드가 더 복잡해질 것이다. 위와 같이 각 단계에서 라우팅 훅을 호출하여 페이지의 넘어감을 관리하면 여러가지 불편함이 있다.
첫 번째로 하나의 ‘회원가입’이라는 목적을 가진 step들인데, 페이지를 바꾸는 것은 각 컴포넌트 내에서 관리를 하고 있기 때문에 관심사가 멀다고 할 수 있다. 나중에 step1과 step2 사이에 step이 하나 추가된다면, 각 step컴포넌트 내부에 들어가 라우팅을 수정해야 한다는 불편함이 있다.
또한, 다른 곳에서 이러한 퍼널 step 구조가 생길 때마다 step 분기 처리, 그리고 각 페이지에서 라우팅하는 과정을 해야 한다.
이러한 과정을 컴포넌트 혹은 훅으로 추상화하여 불편함을 해소하면 어떨까?해서 시작해였다.
Funnel을 사용하는 측에서의 구조를 먼저 작성해보았다. useFunnel훅을 이용하여 Funnel 컴포넌트, prevStep, nextStep함수를 가져올 것이다.
<aside> 🤔 step에 대한 상태는 뭐로 관리하는 것이 좋을까?
후보로는 state + Context를 이용하여 뿌려주기, 전역 상태 관리, query string이 있었다. 우선 이 step이 정말 전역일까? 생각해보았을 때 아니다. step은 이 퍼널 구조에서만 쓰이는 내부 데이터이다. 전역으로 관리하는 것은 불필요하다고 생각하였다.
state + Context를 이용하면 Funnel 컴포넌트 내부에서만 step에 대한 상태를 관리하고, 사용할 수 있다.
query string을 사용했을 때 장점은, 외부에서 해당 퍼널에 들어올 때 특정 step부터 사용자에게 보여줄 수 있다는 점이다. state로 관리할 경우, 이는 어렵고 결국에는 query string을 사용해야 한다.
결론적으로, query string을 활용하기로 결정하였다.
</aside>