폼 제출 중복 클릭, disabled만으로 막기 어려운 이유
폼 제출 버튼의 disabled 처리만으로는 막기 어려운 중복 요청을 화면 상태와 UX 관점에서 정리해요.
폼을 제출하면 버튼을 disabled로 바꾸는 구현은 기본이에요. 사용자는 제출 중이라는 사실을 바로 알 수 있고, 같은 화면에서 2번 누르는 실수도 줄어들어요. 다만 이것만으로 중복 요청까지 막았다고 보기는 어려워요.
간단한 폼을 직접 만들어 보니, 버튼 상태는 화면에 그려진 컴포넌트의 현재 상태일 뿐이었어요. 제출 이벤트가 이미 1회 실행된 뒤 화면 갱신 전에 다시 입력이 들어올 수 있고, 새로고침이나 다른 탭에서는 같은 보호 장치가 공유되지 않아요. 버튼 하나가 비활성화됐다는 사실이 요청 자체를 고유하게 만들지는 않아요.
먼저 화면에는 idle, submitting, success처럼 3가지 상태를 분명히 두는 편이 좋아요. 제출 함수가 시작되면 가장 먼저 submitting인지 확인하고, 진행 중이라면 바로 반환해요. 적용해 봤더니 버튼의 색상만 바꾸는 것보다 안내 문구와 로딩 표시를 함께 두었을 때 사용자가 2번 누를 이유가 훨씬 줄었어요.
if (isSubmitting) return
setIsSubmitting(true)
try {
await submitForm(values)
} finally {
setIsSubmitting(false)
}여기서 중요한 점은 finally예요. 요청이 실패해도 버튼이 계속 잠긴 채 남으면 사용자는 다음 행동을 할 수 없어요. 테스트해 보면 네트워크 오류, 입력값 오류, 서버 오류처럼 실패 경로가 최소 3가지로 나뉠 수 있어요. 각 경우에 재시도할 수 있는 상태로 돌아오는지 확인해야 해요.
또 하나는 요청 식별자예요. 프론트엔드는 제출할 때 1개의 고유 키를 만들어 요청에 함께 보낼 수 있어요. 화면이 다시 열리거나 사용자가 다른 탭에서 제출해도, 처리 쪽에서 같은 키를 2번 반영하지 않도록 설계해야 해요. 돌려 보니 이 구조가 있어야 버튼의 disabled가 놓치는 상황까지 일관되게 다룰 수 있었어요.
라이프케어로그에서 플랜씨(plan-c)처럼 로그인 없이 쓰는 화면을 만들 때도 이 원칙은 같아요. 사용자에게는 즉시 반응하는 버튼과 명확한 상태를 제공하고, 시스템에는 중복을 판별할 기준을 남겨야 해요. disabled는 좋은 시작이지만, 제출 흐름 전체를 지키는 마지막 장치는 아니에요.
관련 글
댓글
아직 댓글이 없어요. 첫 댓글을 남겨주세요.