Error Boundaries ๐Ÿ‘€

Jyerrยท2024๋…„ 8์›” 7์ผ
post-thumbnail

์˜ค๋Š˜์€ Error Boundary๋ผ๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ์•Œ์•„๋ณผ๊ป˜์š”
๊ณต์‹๋ฌธ์„œ ๋ณด๋‹ค๊ฐ€ ๋ฐœ๊ฒฌํ–ˆ์–ด์š” ํžˆํžˆ


๐Ÿ“ฎ Error Boundary

: ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ์˜ ์–ด๋””์—์„œ๋“  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—๋Ÿฌ๋ฅผ ๊ธฐ๋กํ•˜๋ฉฐ ๊นจ์ง„ ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ ๋Œ€์‹  ํด๋ฐฑ UI๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” React ์ปดํฌ๋„ŒํŠธ

๊ณผ๊ฑฐ์—๋Š” ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—๋Ÿฌ๋ฅผ ์ •์ƒ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์—†์—ˆ๋Š”๋ฐ, ์ด์ œ ์—๋Ÿฌ ๋ฐ”์šด๋”๋ฆฌ๋ฅผ ์„ค์ •ํ•ด์ฃผ๋ฉด ๋ฐ”์šด๋”๋ฆฌ ๋‚ด์˜ ์ปดํฌ๋„ŒํŠธ์™€ ๊ทธ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์—๋Ÿฌ๋ฅผ ๊ฐ์ง€ํ•ด์„œ fallback UI๋ฅผ ๋„์–ด์ค„ ์ˆ˜ ์žˆ๊ฒŒ ๋œ๊ฒƒ์ด๋‹ค!!

ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ๋งŒ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๊ณ  ํ•จ์ˆ˜ํ˜•์—์„œ๋„ react-error-boundary๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์—๋Ÿฌ ํŽ˜์ด์ง€๋ฅผ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ๋‹ค




๋ชจ๋“  ์—๋Ÿฌ์—์„œ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•œ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค
์˜ˆ์™ธ์‚ฌํ•ญ๋“ค์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

๐Ÿšจ ์˜ˆ์™ธ
1. ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ
2. ๋น„๋™๊ธฐ์  ์ฝ”๋“œ (์˜ˆ: setTimeout ํ˜น์€ requestAnimationFrame ์ฝœ๋ฐฑ)
3. ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง
4. ์ž์‹์—์„œ๊ฐ€ ์•„๋‹Œ ์—๋Ÿฌ ๊ฒฝ๊ณ„ ์ž์ฒด์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์—๋Ÿฌ

ํŠนํžˆ 4๋ฒˆ์งธ ์˜ˆ์™ธ๋ฅผ ์ฃผ์˜ํ•ด์„œ ๋ด์•ผํ•œ๋‹ค.
Error boundary๋Š” ํŠธ๋ฆฌ ๋‚ด์—์„œ ์ž์‹ ๋ณด๋‹ค ํ•˜์œ„์— ์กด์žฌํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ ์˜ค๋ฅ˜๋งŒ์„ ๊ฐ์ง€ํ•ด๋‚ด๋ฏ€๋กœ ์ฆ‰ , ์ž๊ธฐ ์ž์‹ ์— ๋Œ€ํ•œ ์˜ค๋ฅ˜๋Š” ๊ฐ์ง€ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.




๐Ÿก ์‚ฌ์šฉ๋ฐฉ๋ฒ•

์ƒ๋ช…์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ์ธ static getDerivedStateFromError() ์™€ componentDidCatch() ์ค‘ ํ•˜๋‚˜ (ํ˜น์€ ๋‘˜ ๋‹ค)๋ฅผ ์ •์˜ํ•˜๋ฉด ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ ์ž์ฒด๊ฐ€ ์—๋Ÿฌ ๊ฒฝ๊ณ„๊ฐ€ ๋œ๋‹ค.

1๏ธโƒฃ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ ๋’ค์— ํด๋ฐฑ UI๋ฅผ ๋ Œ๋”๋งํ• ๋ž˜
โžก๏ธ static getDerivedStateFromError()

2๏ธโƒฃ ์—๋Ÿฌ ์ •๋ณด ๊ธฐ๋กํ• ๋ž˜
โžก๏ธ componentDidCatch()

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

  static getDerivedStateFromError(error) {
    // ๋‹ค์Œ ๋ Œ๋”๋ง์—์„œ ํด๋ฐฑ UI๊ฐ€ ๋ณด์ด๋„๋ก ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธ ํ•ฉ๋‹ˆ๋‹ค.
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    // ์—๋Ÿฌ ๋ฆฌํฌํŒ… ์„œ๋น„์Šค์— ์—๋Ÿฌ๋ฅผ ๊ธฐ๋กํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.
    logErrorToMyService(error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      // ํด๋ฐฑ UI๋ฅผ ์ปค์Šคํ…€ํ•˜์—ฌ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
      return <h1>Something went wrong.</h1>;
    }

    return this.props.children;
  }
}

๊ทธ๋ฆฌ๊ณ  ์ผ๋ฐ˜์ปดํฌ๋„ŒํŠธ์™€ ์ด๋Ÿฐ์‹์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค

<ErrorBoundary>
  <MyWidget />
</ErrorBoundary>




๐Ÿ™ try/catch์™€ ๋น„๊ต

try/catch ์™€ Error Boundary ๋ชจ๋‘ ์˜ˆ์™ธ ์ƒํ™ฉ์„ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ์ ์—์„œ ๋น„์Šทํ•˜๋‹ค.
๋‘˜์˜ ์ฐจ์ด๋Š” ์–ด๋–ค๊ฒŒ ์žˆ๋Š”์ง€ ์•Œ์•„๋ณด์ž

1๏ธโƒฃ try/catch

๋ช…๋ นํ˜• ์ฝ”๋“œ์—์„œ๋งŒ ๋™์ž‘ํ•œ๋‹ค. ๋ช…๋ นํ˜• ์ฝ”๋“œ๋Š” ์–ด๋–ป๊ฒŒ(How) ๋™์ž‘ํ• ์ง€๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ์ง€์‹œํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

try {
  showButton();
} catch (error) {
  // ...
}

2๏ธโƒฃ Error Boundary

๊ทธ๋Ÿฌ๋‚˜ ๋ฆฌ์•กํŠธ๋Š” ์„ ์–ธ์ ์ด๋‹ค.์„ ์–ธ์  ์ฝ”๋“œ๋Š” ๋ฌด์—‡(What)์„ ๋ Œ๋”๋งํ• ์ง€ ์„ ์–ธํ•˜๊ณ , ์–ด๋–ป๊ฒŒ(How) ๋ Œ๋”๋ง๋ ์ง€๋Š” React๊ฐ€ ๊ด€๋ฆฌํ•œ๋‹ค. ๋ช…๋ นํ˜• ์ฝ”๋“œ์ธ try/catch์™€ ๋‹ค๋ฅด๊ฒŒ Error Boundary๋Š” ์ด๋Ÿฌํ•œ React์˜ ์„ ์–ธ์ ์ธ ํŠน์„ฑ์„ ๋ณด์กดํ•˜์—ฌ ๋™์ž‘ํ•œ๋‹ค

const App = () => (
  <div>
    <Button />
  </div>
);

โœจ Reference


https://ko.legacy.reactjs.org/docs/error-boundaries.html

profile
๐Ÿคฏ ๐ŸŽ€ ๐Ÿ˜Ž ๐Ÿ™‰ ๐Ÿก

0๊ฐœ์˜ ๋Œ“๊ธ€