웹 개발
로딩 스피너보다 진행 상황을 설명하는 문구가 나을 때
사용자에게 진행 중 상태를 알릴 때, 단순한 로딩 스피너보다 문맥 있는 텍스트가 더 효과적인 경우를 정리했다.
사용자가 기다리는 동안 단순히 스피너만 보여주면 답답해 보인다. 특히 작업이 몇 초 이상 걸리면, 현재 무슨 일이 진행 중인지 알려주는 게 좋다.
예를 들어 "Saving..."보다는 "파일을 저장하는 중입니다" 같은 구체적인 문구가 사용자를 안심시킨다.
스피너만으로는 부족한 이유
- 진행도를 알 수 없다: 사용자는 얼마나 더 기다려야 할지 모른다
- 에러인지 진행 중인지 구분이 안 된다: 화면이 응답 없어 보인다
- 무엇을 하고 있는지 알 수 없다: 무관한 작업처럼 보일 수 있다
좋은 로딩 상태 메시지
// 나쁜 예
<div>
<Spinner />
</div>
// 좋은 예
<div>
<Spinner />
<p>데이터베이스에 저장하는 중입니다...</p>
</div>
// 더 좋은 예 - 진행도 표시
<div>
<ProgressBar value={45} />
<p>이메일 발송 중... (45/100)</p>
</div>
상황별 메시지 예시
파일 업로드:
"파일을 업로드하는 중입니다... (2.3MB / 5MB)"
API 호출:
"서버에서 데이터를 가져오는 중입니다..."
대량 처리:
"50개 항목 중 12개를 처리했습니다..."
생성/변환 작업:
"이미지를 최적화하는 중입니다..."
진행도 표시
특히 오래 걸리는 작업은 진행 상황을 수치로 보여주는 게 효과적이다.
const [progress, setProgress] = useState(0);
return (
<div>
<ProgressBar value={progress} max={100} />
<p>{progress}% 완료</p>
</div>
);
타임아웃 처리
만약 작업이 예상보다 오래 걸리면, 사용자에게 알려야 한다.
const [elapsedTime, setElapsedTime] = useState(0);
effect(() => {
const timer = setInterval(() => setElapsedTime(t => t + 1), 1000);
return () => clearInterval(timer);
}, []);
return (
<div>
<Spinner />
<p>작업이 진행 중입니다...</p>
{elapsedTime > 5 && (
<p style={{color: 'orange'}}>
작업이 예상보다 오래 걸리고 있습니다. 계속 기다려주세요.
</p>
)}
</div>
);
실수하기 쉬운 부분
-
너무 자세한 기술 용어 사용
- "async task queue를 flush하는 중..." → "처리 중입니다..." (간단히)
-
메시지를 자주 바꾸지 않기
- 메시지가 깜빡거리면 산만해 보인다
-
진행도가 멈춘 것처럼 보이기
- 진행도가 100%에 도달했는데 아직 작업 중이면 혼란스럽다
- 마지막 10%를 천천히 채우거나, "마무리하는 중입니다" 메시지 추가
테스트하기
# 속도를 의도적으로 느리게 해서 테스트
const [data, setData] = useState(null);
useEffect(() => {
// 실제 API 호출 대신 의도적 지연
const timer = setTimeout(() => setData({...}), 3000);
return () => clearTimeout(timer);
}, []);
느린 네트워크에서도 로딩 상태가 명확한지 확인한다.
결론
로딩 상태는 사용자 경험의 중요한 부분이다. 스피너만으로 충분하지 않으니, 구체적인 문구와 진행도를 함께 보여주자.