리액트/예제

리액트 앱에서 에러 처리 및 예외 처리 구현하기

lamarcK 2025. 4. 10. 21:08

try catch error문을 통한 에러 관리 구현해보기

 

기본 구조

try {
    // 에러가 발생할 수 있는 코드
    const response = await fetch(`http://localhost:3001/videos?page=${currentPage}&limit=${limit}`);
    // HTTP 에러 체크
    if (!response.ok) { 
        throw new Error(/* 에러 메시지 */);
    }
    // 정상적인 데이터 처리
    const result = await response.json();
} catch (error) {
    // 에러 발생시 실행되는 코드
    setError(error.message);
    console.error('비디오 데이터 로딩 에러:', error);
    // 특정 타입의 에러 처리
    if (error.name === 'TypeError') {
        setError('네트워크 연결을 확인해주세요.');
    }
} finally {
    // 성공/실패 상관없이 항상 실행되는 코드
    setLoading(false);
}

 


1. 에러 상태 관리

const [error, setError] = useState(null); // 에러 상태 초기값은 null

2. 에러 초기

setError(null); // 새로운 데이터 요청 시작할 때 기존 에러 초기화

3. 에러 발생 처리

try {
  // API 요청 코드...
  if (!response.ok) { 
    throw new Error(
      response.status === 404 
        ? '더 이상 비디오를 찾을 수 없습니다.' 
        : `서버 오류가 발생했습니다. (${response.status})`
    );
  }
} catch (error) {
  setError(error.message); // 에러 메시지를 상태에 저장
  console.error('비디오 데이터 로딩 에러:', error);
  
  // 네트워크 에러 특별 처리
  if (error.name === 'TypeError') {
    setError('네트워크 연결을 확인해주세요.');
  }
}

4. 에러 표시 컴포넌트

const ErrorAlert = ({ message, onClose }) => (
  <div className="error-alert">
    <p>{message}</p>
    <button onClick={onClose}>닫기</button>
  </div>
);
  • message: 표시할 에러 메시지
  • onClose: 에러 알림을 닫을 때 실행할 함수
  • 사용자에게 시각적으로 에러를 알리는 UI 컴포넌트

 

 에러 처리 시스템은

  • HTTP 응답 오류 (404 등)
  • 네트워크 오류
  • 서버 오류
    등 다양한 종류의 에러를 처리하고 사용자에게 적절한 메시지를 표시할 수 있습니다.
function VideoList() {
  const [videoData, setVideoData] = useState([]); // 비디오 데이터 목록
  const [currentPage, setCurrentPage] = useState(1); // 현재 페이지 번호 (1부터 시작)
  const [loading, setLoading] = useState(false); // 데이터 로딩 중 상태
  const [hasMore, setHasMore] = useState(true); // 더 로드할 데이터가 있는지 여부
  const limit = PAGE_CONFIG.ITEMS_PER_PAGE;; // 페이지당 불러올 비디오 개수
  const observerTarget = useRef(null); // 📌 감시할 타겟 요소 Ref
  const mountedRef = useRef(false); // 추가: 마운트 상태 추적을 위한 ref
  const { isNavExpanded } = useContext(NavContext); // 이제 정상 작동
  const [error, setError] = useState(null); //에러 처리

  // ✨ 비디오 데이터를 로드하는 함수 (페이지네이션 적용)
  const loadVideos = useCallback(async () => {
    // 로딩 중이거나 더 이상 데이터가 없으면 실행 중지
    if (loading || !hasMore) return;

    setLoading(true);
    setError(null); // 새로운 요청 시작 시 에러 초기화
    
    try {
      // 📌 API 요청 URL 변경: `offset` 대신 `page`와 `limit` 사용
      const response = await fetch(`http://localhost:3001/videos?page=${currentPage}&limit=${limit}`);
      if (!response.ok) { // HTTP 응답 상태 확인
          throw new Error(
            response.status === 404 
              ? '더 이상 비디오를 찾을 수 없습니다.' 
              : `서버 오류가 발생했습니다. (${response.status})`
          );
        }
    

      // 📌 API 응답 구조 변경에 따른 처리
      //    - 백엔드가 { data: [...], pagination: {...} } 형태로 응답
      const result = await response.json();
      const newVideos = result.data; // 실제 비디오 데이터 배열
      const pagination = result.pagination; // 페이지네이션 정보

      console.log(`[Frontend] Loaded page ${pagination.currentPage}/${pagination.totalPages}, Videos: ${newVideos.length}`);

      // 받아온 비디오 데이터가 있으면 기존 목록에 추가
      if (newVideos.length > 0) {
        setVideoData(prev => [...prev, ...newVideos]);
      }

      // 📌 더 로드할 데이터가 있는지 판단 (hasMore 상태 업데이트)
      //    - 현재 페이지가 총 페이지 수보다 크거나 같으면 더 이상 데이터가 없음
      if (pagination.currentPage >= pagination.totalPages) {
        setHasMore(false);
        console.log("[Frontend] No more videos to load.");
      } else {
         // 다음 페이지 로드를 위해 현재 페이지 번호 증가 (다음번 loadVideos 호출 시 사용됨)
         setCurrentPage(prevPage => prevPage + 1);
      }

    } catch (error) {
      setError(error.message);
      console.error('비디오 데이터 로딩 에러:', error);
      // 네트워크 오류의 경우 재시도 로직 추가
      if (error.name === 'TypeError') {
        setError('네트워크 연결을 확인해주세요.');
      }
    } finally {
      // 로딩 상태 해제 (성공/실패 여부와 관계없이 실행)
      setLoading(false);
    }
  }, [currentPage, hasMore, loading, limit]); // useCallback 의존성 배열 업데이트

// 에러 알림 컴포넌트트
const ErrorAlert = ({ message, onClose }) => (
  <div className="error-alert">
    <p>{message}</p>
    <button onClick={onClose}>닫기</button>
  </div>
);