일상이 개발

React 토스트/알림 시스템 설계 가이드 – 전역 상태부터 자동 닫힘, 접근성까지 완벽 정리

아빠고미 2025. 5. 3. 12:55
반응형

React 토스트/알림/스낵바 시스템 제대로 설계하기 – 전역 상태, 중첩 알림, 자동 닫힘까지 UI 알림의 모든 것

사용자가 어떤 행동을 했을 때 적절한 피드백을 주는 것, 그게 바로 알림 시스템의 핵심입니다.

React 앱에서는 이를 위해 흔히 "토스트", "스낵바", "알림 컴포넌트" 등을 사용하죠. 그런데 이 단순해 보이는 기능도 제대로 만들려면 고려할 것이 정말 많습니다:

  • ✅ 전역 상태로 알림을 관리할 것인가?
  • ✅ 여러 개의 알림이 동시에 떠도 괜찮을까?
  • ✅ 자동으로 사라지게 할 건가, 수동으로 닫게 할 건가?
  • ✅ 알림의 우선순위나 타입은 어떻게 처리할까?
  • ✅ 모바일/웹 둘 다 대응 가능해야 하지 않을까?

이번 글에서는 위와 같은 고민을 해결하기 위한 실전 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도 뛰어난 알림 시스템을 도입해보세요!


글이 유익했다면 댓글, 공감, 공유로 응원해주세요 🙌

반응형