상태 기반 흐름 전환
TeachTouch : 디지털 약자를 위한 키오스크 학습 가이드 서비스📚
Github: 2025_SEASONTHON_TEAM_77_FE
2025.09
상태 기반 흐름 전환
가이드를 구현하는 중 각 카테고리별로 화면이 너무 다르게 생겨서 공용 컴포넌트를 만들어 여러 카테고리에서 사용하긴 어려워보였다.
-> 카테고리별로 컴포넌트를 만들고 그 안에서 제어하기로 결정
그렇다면 학습 시나리오를 어떻게 구성해야할까. 고려사항은 다음과 같았다.
- 각 카테고리는 intro, content, complete라는 흐름으로 진행
- intro, content, complete 화면이 각각 전환되지만 화면 구조는 크게 다르지 않고, 각 단계는 동일한 컴포넌트 위에 모달, 툴팁, 오버레이, 하드웨어 위치 강조 등 시각적 요소들이 쌓이며 변화
- 특정 조건이 충족될 때 다음 단계로 넘어갈 수 있도록
- 카테고리 내부 상태는 저장될 필요 없이 시작과 끝만 저장되면 됨
- 사용자의 경로는 시작과 끝을 통해서만 이동(중간 콘텐츠로 url 변경해서 들어갈 수 없도록)
따라서 하나의 컴포넌트 내부에서 상태를 기반으로 전체 흐름을 관리하기로 결정했다.
이유는?
- 라우팅 기반 전환은 url 변경을 수반하므로 사용자가 url을 직접 변경해 중간 과정으로 들어갈 수도 있음
- 특정 조건이 충족될 때만 다음 단계로 넘어갈 수 있도록 해야 하는데 사용자가 url 직접 입력, 뒤로가기, F5 등으로 의도되지 않은 이동을 할 수 있어 학습 시나리오가 깨질 수 있음
- 화면 간 전환보다는 같은 뷰 안에서 맥락의 변화를 표현해야 하는 경우에 가까움
구현 방식
const [page, setPage] = useState<'intro' | 'content' | 'complete'>('intro');
현재 보여줄 화면을 결정하는 라우터 역할
intro와 complete 단계에선 IntroScreen, CompleteScreen컴포넌트를 만들어서 여러 카테고리에서 재활용했다.
안에 content 부분은
if (step !== null && step < structureSteps.length - 1) {
setStep(step + 1);
} else {
setStep(null);
setPage('complete');
}
step을 사용해 화면 내 세부 단계를 제어하게 했다.
확실히 useState를 쓰다보니 코드가 길어진 감이 있긴 하다. 단순한 페이지 흐름 제어에서 useState를 쓴 것은 나름 합리적인 선택이긴 했지만 다른 대안들도 있었을 것 같다.
- useReducer
const reducer = (state, action) => { switch(action.type) { case 'TO_CONTENT': return { page: 'content', step: 0 }; case 'NEXT_STEP': return { ...state, step: state.step + 1 }; ... } }상태 간 의존성이 있거나 전이가 복잡할 경우에 유용하다는데 우린 단순하므로 패스
- useSearchParams, useLocation + useNavigate
const [searchParams, setSearchParams] = useSearchParams(); useEffect(() => { const step = Number(searchParams.get('step')) || 0; setStep(step); }, []);학습을 도중에 나갔다가 다시 이어서 해야 하는 경우가 있다면 유용할 것 같다.
-
Redux, Zustand 등 전역 상태
학습 완료율 등을 추적하는 대시보드 등과 연동하거나 전역으로 학습 흐름 상태를 관리해야 한다면 유용할 것 같다. 하지만 해커톤이기도 하고 전역 상태는 비용이 과도할 것 같다는 생각에 패스
지금 단계에서는 useState로도 충분하지만 확장을 고려한다면 다른 훅을 고려해봐도 좋을 것 같다.