본문 바로가기

FrontEnd

[Epic React] Errorboundary로 선언적 에러 핸들링

반응형

리액트

왜 ErrorBoundary를 쓰나요

  • 선언적 에러 핸들링
  • 자바스크립트 런타임 에러와 비동기 에러를 동시 처리
  • 하위 컴포넌트 에러를 상위 컴포넌트에서 처리

 

사용방법 1 : 직접 구현하기

에러바운더리는 현재 클래스 컴포넌트만 사용할 수 있음

1. 에러바운더리 컴포넌트 만들기

static getDerivedStateFromError 메소드를 구현함. (error) 꺼내옴

props의 FallbackComponent에 error를 전달후 렌더링

에러 없으면 children 렌더링

class ErrorBoundary extends React.Component {
  state = {error: null}
  static getDerivedStateFromError(error) {
    return {error}
  }
  render() {
    const {error} = this.state
    if (error) {
      return <this.props.FallbackComponent error={error} />
    }

    return this.props.children
  }
}

2. FallbackComponent 만들기

function ErrorFallback({error}) {
  return (
    <div role="alert">
      There was an error:{' '}
      <pre style={{whiteSpace: 'normal'}}>{error.message}</pre>
    </div>
  )
}

3. key속성을 통해 ErrorBoundary Re-mount(에러초기화)

function App() {
  const [pokemonName, setPokemonName] = React.useState('')

  function handleSubmit(newPokemonName) {
    setPokemonName(newPokemonName)
  }

  return (
    <div className="pokemon-info-app">
      <PokemonForm pokemonName={pokemonName} onSubmit={handleSubmit} />
      <hr />
      <div className="pokemon-info">
      	/** 여기 주목 **/
        <ErrorBoundary key={pokemonName} FallbackComponent={ErrorFallback}>
          <PokemonInfo pokemonName={pokemonName} />
        </ErrorBoundary>
      </div>
    </div>
  )
  }

참고 : PokemonInfo 컴포넌트

react-hooks/pokemon.js at main · kentcdodds/react-hooks (github.com)

 

GitHub - kentcdodds/react-hooks: Learn React Hooks! 🎣 ⚛

Learn React Hooks! 🎣 ⚛. Contribute to kentcdodds/react-hooks development by creating an account on GitHub.

github.com

react-hooks/06.extra-5.js at main · kentcdodds/react-hooks (github.com)

 

GitHub - kentcdodds/react-hooks: Learn React Hooks! 🎣 ⚛

Learn React Hooks! 🎣 ⚛. Contribute to kentcdodds/react-hooks development by creating an account on GitHub.

github.com

function PokemonInfo({pokemonName}) {
  const [state, setState] = React.useState({
    status: 'idle',
    pokemon: null,
    error: null,
  })
  const {status, pokemon, error} = state

  React.useEffect(() => {
    if (!pokemonName) {
      return
    }
    setState({status: 'pending'})
    fetchPokemon(pokemonName).then(
      pokemon => {
        setState({status: 'resolved', pokemon})
      },
      error => {
        setState({status: 'rejected', error})
      },
    )
  }, [pokemonName])

  if (status === 'idle') {
    return 'Submit a pokemon'
  } else if (status === 'pending') {
    return <PokemonInfoFallback name={pokemonName} />
  } else if (status === 'rejected') {
    // this will be handled by an error boundary
    throw error
  } else if (status === 'resolved') {
    return <PokemonDataView pokemon={pokemon} />
  }

  throw new Error('This should be impossible')
}

function ErrorFallback({error}) {
  return (
    <div role="alert">
      There was an error:{' '}
      <pre style={{whiteSpace: 'normal'}}>{error.message}</pre>
    </div>
  )
}

 

사용방법 2 : 남이 만든 라이브러리 가져다 쓰기

react-error-boundary를 사용한다.

react-hooks/06.extra-8.js at main · kentcdodds/react-hooks (github.com)

 

GitHub - kentcdodds/react-hooks: Learn React Hooks! 🎣 ⚛

Learn React Hooks! 🎣 ⚛. Contribute to kentcdodds/react-hooks development by creating an account on GitHub.

github.com

1. 아까 만든 클래스 컴포넌트를 지운다

2. (Option) ErrorFallback 컴포넌트에서 ErrorBoundary를 리셋시킬 수 있는 resetErrorBoundary함수를 사용한다.

function ErrorFallback({error, resetErrorBoundary}) {
  return (
    <div role="alert">
      There was an error:{' '}
      <pre style={{whiteSpace: 'normal'}}>{error.message}</pre>
      <button onClick={resetErrorBoundary}>Try again</button>
    </div>
  )
}

3. 사용하는 곳을 다음과 같이 바꾼다.

fallbackComponent는 동일

onReset(new) : 에러가 리셋될 때 호출할 함수 설정

resetKeys(new) : 클래스 컴포넌트의 key에 대응. 의존성 배열처럼 사용.

import {ErrorBoundary} from 'react-error-boundary'

function App() {
  const [pokemonName, setPokemonName] = React.useState('')

  
  function handleSubmit(newPokemonName) {
    setPokemonName(newPokemonName)
  }
  // error reset되면 호출할 함수
  function handleReset() {
    setPokemonName('')
  }

  return (
    <div className="pokemon-info-app">
      <PokemonForm pokemonName={pokemonName} onSubmit={handleSubmit} />
      <hr />
      <div className="pokemon-info">
        <ErrorBoundary
          FallbackComponent={ErrorFallback} // Fallback시 렌더링할 컴포넌트.
          onReset={handleReset}
          resetKeys={[pokemonName]} // 클래스 컴포넌트의 key와 동일한 역할.
        >
          <PokemonInfo pokemonName={pokemonName} />
        </ErrorBoundary>
      </div>
    </div>
  )
}
반응형