반응형
문제 상황
비밀번호 재설정 기능을 구현하던 중, 성공 메시지와 카운트다운 타이머가 전혀 동작하지 않는 버그를 발견했습니다. 코드를 살펴보니 성공 UI와 관련된 로직이 완전히 데드코드(Dead Code)가 되어 있었습니다.
// 이 코드는 절대 실행되지 않았습니다
{actionData && 'success' in actionData && (
<div className="text-green-600 text-sm text-center">
비밀번호가 성공적으로 변경되었습니다! 로그인 페이지로 이동합니다...
{countdown > 0 && ` (${countdown}초)`}
</div>
)}
// 이 useEffect도 마찬가지로 실행되지 않았습니다
useEffect(() => {
if (actionData && 'success' in actionData) {
setCountdown(3)
// 카운트다운 로직...
}
}, [actionData])
원인 분석
문제의 핵심은 Server Action과 Client UI 간의 데이터 흐름에 있었습니다.
기존 코드의 흐름
export async function action({ request }: ActionFunctionArgs) {
// 비밀번호 재설정 로직...
// 성공 시 즉시 리다이렉트
return redirect(`${ROUTES.LOGIN}?message=password_reset_success`)
}
- 사용자가 폼을 제출
action함수에서 비밀번호 재설정 처리- 성공 시 즉시
redirect()호출 - 클라이언트는 새로운 페이지로 이동
actionData에는 아무 데이터도 전달되지 않음
결과적으로 actionData에는 절대 success 프로퍼티가 포함되지 않았고, 성공 UI는 렌더링될 기회가 없었습니다.
해결 방안
1. Server Action 수정
즉시 리다이렉트하는 대신 성공 상태를 JSON으로 반환하도록 변경했습니다.
export async function action({ request }: ActionFunctionArgs) {
// 비밀번호 재설정 로직...
// 변경 전: 즉시 리다이렉트
// return redirect(`${ROUTES.LOGIN}?message=password_reset_success`)
// 변경 후: 성공 상태 반환
return json({ success: true }, {
headers: response.headers
})
}
2. Client-side 리다이렉트 로직 추가
useNavigate 훅을 사용하여 카운트다운 완료 후 클라이언트에서 리다이렉트하도록 구현했습니다.
import { useNavigate } from '@remix-run/react'
export default function ResetPasswordPage() {
const navigate = useNavigate()
// 성공 메시지 카운트다운 및 리다이렉트
useEffect(() => {
if (actionData && 'success' in actionData) {
setCountdown(3)
const timer = setInterval(() => {
setCountdown((prev) => {
if (prev <= 1) {
clearInterval(timer)
// 카운트다운 완료 시 로그인 페이지로 리다이렉트
navigate(`${ROUTES.LOGIN}?message=password_reset_success`)
return 0
}
return prev - 1
})
}, 1000)
return () => clearInterval(timer)
}
}, [actionData, navigate])
}
수정된 데이터 흐름
새로운 흐름
- 사용자가 폼을 제출
action함수에서 비밀번호 재설정 처리- 성공 시
{ success: true }JSON 반환 - 클라이언트가
actionData를 통해 성공 상태 확인 - 성공 메시지 UI 렌더링 및 카운트다운 시작
- 카운트다운 완료 후 클라이언트에서 리다이렉트
핵심 교훈
1. Server Action의 응답 방식 선택
- 즉시 리다이렉트: 빠른 페이지 전환이 필요한 경우
- 데이터 반환: 클라이언트에서 추가 처리가 필요한 경우
2. UX 고려사항
이번 수정으로 사용자는:
- ✅ 성공 메시지를 명확히 확인할 수 있음
- ✅ 3초 카운트다운으로 다음 동작을 예상할 수 있음
- ✅ 자동으로 적절한 페이지로 이동함
3. 데드코드 방지
Server-Client 간 데이터 흐름을 명확히 이해하고, 작성한 UI 코드가 실제로 실행될 수 있는 조건을 만족하는지 확인해야 합니다.
마무리
이 버그는 Remix의 Server Action과 Client UI 간 데이터 흐름을 제대로 이해하지 못해서 발생한 전형적인 케이스였습니다. 특히 redirect()와 json() 반환의 차이점을 명확히 이해하는 것이 중요합니다.
비슷한 문제를 겪고 있다면, 다음을 확인해보세요:
- Action 함수에서 반환하는 응답 형태
- 클라이언트에서
actionData를 통해 받을 수 있는 데이터 - UI 렌더링 조건과 실제 데이터 흐름의 일치 여부
반응형
'🧑💻 바이브 코딩' 카테고리의 다른 글
| 혼자여도 맛있고, 간단하게 - 밥풀 (0) | 2025.10.03 |
|---|---|
| [바이브 코딩 #8] 데이트 코스 추천 서비스 개발기 (5) | 2025.07.12 |
| [바이브 코딩 #7] 데이트 코스 추천 서비스 개발기 (3) | 2025.07.03 |
| [바이브 코딩 #6] 데이트 코스 추천 서비스 개발기 (0) | 2025.06.29 |
| [바이브 코딩 #5] 데이트 코스 추천 서비스 개발기 (1) | 2025.06.28 |