React 토스트/알림 시스템 설계 가이드 – 전역 상태부터 자동 닫힘, 접근성까지 완벽 정리
React 토스트/알림/스낵바 시스템 제대로 설계하기 – 전역 상태, 중첩 알림, 자동 닫힘까지 UI 알림의 모든 것
사용자가 어떤 행동을 했을 때 적절한 피드백을 주는 것, 그게 바로 알림 시스템의 핵심입니다.
React 앱에서는 이를 위해 흔히 "토스트", "스낵바", "알림 컴포넌트" 등을 사용하죠. 그런데 이 단순해 보이는 기능도 제대로 만들려면 고려할 것이 정말 많습니다:
- ✅ 전역 상태로 알림을 관리할 것인가?
- ✅ 여러 개의 알림이 동시에 떠도 괜찮을까?
- ✅ 자동으로 사라지게 할 건가, 수동으로 닫게 할 건가?
- ✅ 알림의 우선순위나 타입은 어떻게 처리할까?
- ✅ 모바일/웹 둘 다 대응 가능해야 하지 않을까?
이번 글에서는 위와 같은 고민을 해결하기 위한 실전 React 알림 시스템 설계 전략을 총정리합니다.
1. 📌 알림 UI의 3대 조건
1) 즉각적인 사용자 피드백
- 동작 성공 여부, 예외 발생, 주의 환기 등 명확한 메시지를 즉시 제공해야 함
2) UX 흐름 방해 금지
- 알림이 떠도 사용자의 행동을 막으면 안 됨
- 필요 이상으로 알림이 길게 남아있거나, 겹쳐서 보이면 혼란 발생
3) 시각적 일관성과 접근성
- 항상 동일한 위치, 동일한 전환 애니메이션
- 화면리더, 키보드 유저도 접근 가능하도록 설계
✅ 이 세 가지를 만족하려면, 단순한 컴포넌트가 아니라 **알림 시스템**을 설계해야 합니다.
2. 🌐 알림 시스템을 위한 전역 상태 설계
React에서 알림 시스템을 효과적으로 구현하려면, 어디서든 showToast()
같은 함수를 호출해 토스트 메시지를 띄울 수 있어야 합니다.
이를 위해선 알림을 전역 상태로 관리하는 구조가 필요해요.
✅ 전역 알림 스토어 구조 예시 (Zustand)
// useToastStore.js
import { create } from 'zustand';
export const useToastStore = create((set) => ({
toasts: [],
showToast: (toast) =>
set((state) => ({
toasts: [...state.toasts, { id: Date.now(), ...toast }],
})),
removeToast: (id) =>
set((state) => ({
toasts: state.toasts.filter((t) => t.id !== id),
})),
}));
✅ 알림 객체 구조 예시
{
id: 171293847239,
message: "회원가입이 완료되었습니다.",
type: "success", // info, error, warning 등
duration: 3000,
}
이렇게 하면 useToastStore()
를 통해 어디서든 알림을 추가하거나 제거할 수 있습니다.
3. 🧱 토스트 컴포넌트 구조 설계
알림 UI는 단일 컴포넌트가 아니라, 컨테이너 + 개별 아이템으로 나누어 설계하는 것이 좋습니다.
📦 예시 구조
components/
└── Toast/
├── ToastContainer.jsx
├── ToastItem.jsx
└── useToast.js
✅ ToastContainer.jsx
function ToastContainer() {
const { toasts, removeToast } = useToastStore();
return (
<div className="toast-wrapper">
{toasts.map((toast) => (
<ToastItem key={toast.id} {...toast} onClose={() => removeToast(toast.id)} />
))}
</div>
);
}
✅ ToastItem.jsx
function ToastItem({ message, type = 'info', duration = 3000, onClose }) {
useEffect(() => {
const timer = setTimeout(onClose, duration);
return () => clearTimeout(timer);
}, [duration]);
return (
<div className={`toast toast-${type}`}>
{message}
</div>
);
}
✅ useToast.js
export const useToast = () => {
const { showToast } = useToastStore();
return showToast;
};
이렇게 분리하면, 추가/제거/타입별 스타일/전환 효과/접근성을 각각 독립적으로 관리할 수 있어요.
4. 🔁 알림 우선순위와 큐 관리 전략
사용자가 빠르게 여러 동작을 하면 알림이 연달아 뜨기도 합니다. 이때 알림이 겹쳐서 보이거나, 중복 메시지가 동시에 나타나면 UX는 혼란스러워져요.
✅ 해결 전략
- 동일한 메시지 반복 시 → 무시하거나 덮어쓰기
- 한 번에 보여줄 수 있는 알림 수 제한 (예: 최대 3개)
- 알림 큐를 만들어 순차적으로 보여주기
📦 예: 알림 큐 로직
if (toasts.length >= 3) {
// 큐에 넣고, 기존 알림 제거 후 띄움
setToastQueue((prev) => [...prev, newToast]);
} else {
showToast(newToast);
}
5. ⏱️ 자동 닫힘 처리와 수동 제어
토스트는 대개 자동으로 닫히는 시간(duration)을 가집니다. 하지만 때로는 유저가 직접 닫는 버튼도 필요하죠.
✅ 자동 닫힘 구현
useEffect(() => {
const timer = setTimeout(onClose, duration);
return () => clearTimeout(timer);
}, []);
✅ 수동 닫기 버튼
<button onClick={onClose} aria-label="닫기">✖</button>
👉 닫기 버튼은 aria-label
로 접근성을 보장하세요.
6. 🧠 마무리 – UX 중심의 알림 시스템을 설계하자
알림은 단순한 UI 피드백이 아니라, 앱 전체의 사용자 경험을 좌우하는 핵심 요소입니다.
✨ 핵심 설계 요약
- 알림은 전역 상태(Zustand/Context)로 관리하자
- Container와 Item을 분리해 구조화하자
- 자동 닫힘/수동 닫기/우선순위 처리를 유연하게
- 접근성과 반응성(모바일 대응)도 함께 고려
- 사용자 행동에 즉각 반응하도록 빠르게 처리
이제 여러분의 React 앱에도 기능적으로 완성도 있고, UX도 뛰어난 알림 시스템을 도입해보세요!
글이 유익했다면 댓글, 공감, 공유로 응원해주세요 🙌