1. 기존의 불편함

회원가입 페이지 같은 경우, 여러 단계들로 이루어져 있다. 이러한 구조를 퍼널 패턴이라 한다. 주로 마케팅 분야에서 많이 사용되며, 구매 과정에서 고객이 거치는 여러 단계를 설명할 대 사용되는 용어이다.

만약, 퍼널의 각 단계에 대한 상태를 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 분기 처리, 그리고 각 페이지에서 라우팅하는 과정을 해야 한다.

이러한 과정을 컴포넌트 혹은 훅으로 추상화하여 불편함을 해소하면 어떨까?해서 시작해였다.

2. 개발 설계

Funnel을 사용하는 측에서의 구조를 먼저 작성해보았다. useFunnel훅을 이용하여 Funnel 컴포넌트, prevStep, nextStep함수를 가져올 것이다.

  1. Funnel은 퍼널 스탭에 대한 상태를 뿌려주는 퍼널 구조를 감싸는 래퍼역할을 한다.
  2. prevStep, nextStep, setStep을 이용하여 이전 스탭 혹은 다음 스탭으로, 혹은 원하는 스탭으로 이동할 수 있다.
  3. currentStep프로퍼티를 이용하여 현재 스탭에 대한 정보를 얻을 수 있다.

3. 코드 작성하기

<aside> 🤔 step에 대한 상태는 뭐로 관리하는 것이 좋을까?

후보로는 state + Context를 이용하여 뿌려주기, 전역 상태 관리, query string이 있었다. 우선 이 step이 정말 전역일까? 생각해보았을 때 아니다. step은 이 퍼널 구조에서만 쓰이는 내부 데이터이다. 전역으로 관리하는 것은 불필요하다고 생각하였다.

state + Context를 이용하면 Funnel 컴포넌트 내부에서만 step에 대한 상태를 관리하고, 사용할 수 있다.

query string을 사용했을 때 장점은, 외부에서 해당 퍼널에 들어올 때 특정 step부터 사용자에게 보여줄 수 있다는 점이다. state로 관리할 경우, 이는 어렵고 결국에는 query string을 사용해야 한다.

결론적으로, query string을 활용하기로 결정하였다.

</aside>

1. 인터페이스 설계하기