플로고 Main Flow 구축 기록 (Part 2) - Signup + Agreement 페이지

오병훈·2025년 4월 28일
0

🧩 Signup 페이지 (회원가입)

1. 페이지 개요

  • 사용자가 성별, 거주 지역, 닉네임, 프로필 이미지를 입력하고 다음 단계(약관 동의)로 넘어가는 폼 페이지입니다.

  • UX를 고려해 필수 항목(성별, 지역, 닉네임) 입력 시에만 버튼이 활성화되도록 했습니다.

  • 프로필 이미지는 선택 사항으로 관리했습니다.


2. 고민 과정

후보장단점최종 선택
React Hook Form 사용✅ 폼 상태 통합 관리 가능
✅ Validation(검증) 편리
✅ 성능 최적화 (re-render 최소화)
✅ 커스텀 입력 컴포넌트 적용 쉬움
useState로 직접 관리❌ 필드마다 상태 변수 관리 → 코드 복잡
❌ 중복 로직 증가
Formik + Yup 조합✅ 고급 검증 가능
❌ 비교적 셋업 복잡 (Next.js App Router 초기 프로젝트에는 과함)

👉 결론: 프로젝트 규모, 요구사항(필수 입력 검증) 기준 React Hook Form이 가장 효율적.


3. 세부 구현 흐름

  • FormProvider를 사용해 Context 기반으로 form 상태를 하위 컴포넌트에 전달

  • watchgender, region, nickname 값을 모니터링해, 모두 입력된 경우만 '다음' 버튼 활성화

  • handleSubmit으로 form 제출시 데이터 수집

  • onSubmit에서는 현재는 console.log로 출력하고, 추후 서버로 전송 예정

  • 프로필 이미지는 업로드 선택사항 → 별도 validation 없이 관리


4. 주요 코드

"use client";

import { FormProvider, useForm } from "react-hook-form";
import { useRouter } from "next/navigation";

export default function SignupPage() {
  const router = useRouter();
  const methods = useForm<SignupFormValues>({ mode: "onChange" });
  const { handleSubmit, watch, formState: { isValid } } = methods;

  const gender = watch("gender");
  const region = watch("region");
  const nickname = watch("nickname");

  const isAllRequiredFilled = gender && region && nickname;

  const onSubmit = (data: SignupFormValues) => {
    console.log("회원가입 데이터:", data);
    router.push("/agreement");
  };

  return (
    <FormProvider {...methods}>
      <form onSubmit={handleSubmit(onSubmit)}>
        {/* 입력 컴포넌트들 */}
        <button type="submit" disabled={!isValid || !isAllRequiredFilled}>
          다음
        </button>
      </form>
    </FormProvider>
  );
}

🔵 포인트: isValid + watch 결과를 함께 체크하여 form 전체 완성 여부를 즉시 반영하는 로직을 구성.


5. 배운 점

  • React Hook Form을 제대로 활용하면 별도 상태 관리 없이 매우 깔끔한 폼 로직이 가능하다는 걸 체감함.

  • 특히 FormProvider 패턴은 복잡한 폼 컴포넌트를 분리할 때 유지보수성이 뛰어나다는 것을 경험.

방법장점
FormProvider + useFormContext 사용✅ props 없이 폼 상태 접근 가능
✅ 컴포넌트 재사용성 높음
✅ 유지보수 쉬움

FormProvider로 감싸서, FormInput 내부에서는 useFormContext만 호출하면 register, errors를 사용할 수 있다.


🧩 Agreement 페이지 (약관 동의)

1. 페이지 개요

  • 회원가입 직후, 사용자가 필수 약관(3개)에 모두 동의해야만 다음 단계로 이동할 수 있는 페이지

  • 각각의 약관을 '보기' 버튼으로 열어 자세히 확인 가능

  • 전체 동의, 개별 동의 모두 지원


2. 고민 과정

후보장단점최종 선택
커스텀 체크박스 + 팝업 설계✅ 디자인 자유도 높음
✅ 약관 보기 팝업 커스텀 가능
✅ UX 맞춤형 제어 가능
기본 <input type="checkbox"> 사용❌ 디자인 제한
❌ 팝업 트리거 구현 불편
외부 컴포넌트 라이브러리 사용❌ 프로젝트 경량성을 해침

👉 결론: 플로고의 감성(경량 + 심플 UX) 유지 위해 직접 커스텀 구현.


3. 세부 구현 흐름

  • 각 약관별 동의 여부를 agreements 객체 상태로 관리

  • 전체 동의는 Object.values(agreements).every(Boolean)로 체크

  • 보기 버튼 클릭 시, 해당 약관 내용을 팝업으로 띄움

  • 팝업에서 '확인' 클릭 시 동의 처리 및 팝업 닫기

  • 모두 동의해야 '확인' 버튼 활성화


4. 주요 코드

const [agreements, setAgreements] = useState<Record<string, boolean>>({
  terms: false,
  privacy: false,
  location: false,
});

const isAllChecked = Object.values(agreements).every(Boolean);

const handlePopupConfirm = (id: string) => {
  setAgreements(prev => ({ ...prev, [id]: true }));
  setSelectedPopup(null);
};

🔵 포인트: Record<string, boolean> 구조를 사용해 확장성과 코드 간결성 둘 다 확보.


5. 배운 점

  • 약관 팝업을 단순 모달이 아니라 페이지 전환처럼 구성함으로써 모바일 UX를 부드럽게 만들 수 있었다.

  • 상태 설계만 신경쓰면 복잡해 보이는 흐름도 boolean 조합만으로 충분히 해결 가능.

profile
Front-End Developer

0개의 댓글