본문 바로가기

React

react - 예외 처리 방법


1. UI 렌더링 과정의 예외처리

* Error Boundary(React 16에서 도입)
- 해당 컴포넌트를 최상위 컴포넌트로 만들면, 생명주기에서 발생하는 모든 예외 처리 가능.

- 자식 컴포넌트에서 에러 발생시 호출되므로, 메세지 렌더링에 실패하면 위쪽으로 전파됨.

- getDerivedStateFromError : rener 과정에서 호출됨. Error 를 UI에 보여주는 용도로 사용.

- componentDidCatch : 자식컴포넌트에서 오류 발생시, 가장 마지막에 호출.

   에러 정보를 기록하는 등 side effect 용도로 사용.

- ErrorBoundary컴포넌트로 처리되지 않은 에러 발생시, 모든 컴포넌트 언마운트. 따라서 폴백 UI를 보여줘야함.

- 생명주기 메서드가 아닌 곳에서 발생한 에러는 잡을 수 없음.

- Hooks에서 사용 불가능...

- try/catch와 차이 : 명령형 코드가 아닌 곳(컴포넌트 등)에서 사용.

- 이벤트핸들러와 차이 : 모든 컴포넌트 언마운트.

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    console.error("error:", error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
    
    // UI렌더링
      return <p>{error.toString()}</p>;
    }
    return this.props.children;
  }
}

function App() {
  return (
    <div>
      <ErrorBoundary>
        <getUser />
      </ErrorBoundary>
    </div>
  );
}


* 조건부 렌더링
- 에러 발생 가능성이 있는 컴포넌트에 조건부 렌더링을 적용.

function getUser({ user }) {

//
  if (!user) {
    return <div>존재하지 않는 사용자입니다.</div>;
  }
//

  return (
    <div>
      <p>{user.name}</p>
      <p>{user.email}</p>
    </div>
  );
}



2. 비동기 데이터 처리과정의 예외처리
* Promise

function fetchUser(userId) {
  return fetch(`https://api.example.com/users/${userId}`)
    .then((response) => {
      if (!response.ok) {
        throw new Error('에러 발생');
      }
      return response.json();
    })
    .catch((error) => {
      console.error('에러 발생 : ', error);
    });
}


* async/await

async function fetchUser(userId) {
  try {
    const response = await fetch(`https://api.example.com/users/${userId}`);
    if (!response.ok) {
      throw new Error('에러 발생');
    }
    const userData = await response.json();
    return userData;
  } catch (error) {
    console.error('에러 발생 : ', error);
  }
}



3. 컴포넌트의 예외 처리
* state를 사용하여 에러 정보 저장.

import React, { useState, useEffect } from 'react';

function User({ userId }) {
  const [user, setUser] = useState(null);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const data = await fetchUser(userId);
        setUser(data);
      } catch (error) {
      
      //
        setError(error.message);
       //
      }
    };

    fetchData();
  }, [userId]);

  if (error) {
    return <div>에러: {error}</div>;
  }

  if (!user) {
    return <div>fetch중</div>;
  }

  return (
    <div>
      <p>{user.name}</p>
      <p>{user.email}</p>
    </div>
  );
}