React Error Boundaries๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ ๊ฒช์€ ์ผ

React Error Boundaries๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด try catch์™€ ๊ฐ™์€ ๋ฐฉ๋ฒ•์œผ๋กœ ์—๋Ÿฌ๋ฅผ ์žก์ง€ ์•Š์Šต๋‹ˆ๋‹ค

Profile Picture
Yoon-Hae-Min
2023-12-12

์ด ๊ฒŒ์‹œ๊ธ€์˜ ์›๋ณธ ๋ธ”๋กœ๊ทธ์ž…๋‹ˆ๋‹ค.

React ๋‚ด๋ถ€์—์„œ ์—๋Ÿฌ๋ฅผ ์ฒ˜๋ฆฌํ•œ๋‹ค ํ•˜๋ฉด try catch ๋ฌธ์„ ์ด์šฉํ•ด์„œ ์—๋Ÿฌ๋ฅผ ํ•ธ๋“ค๋งํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ฐ”๋กœ ๋– ์˜ฌ๋ฆด ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋Š” ๋ช…๋ น์ ์œผ๋กœ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์งœ๋Š” ๊ฒƒ์ธ๋ฐ์š”.

function riskyFunction() {
  if (Math.random() < 0.5) {
    throw new Error("Something went wrong!");
  }
  return "Success!";
}

try {
  const result = riskyFunction();
  console.log(result);
} catch (error) {
  console.error("Caught an error:", error);
}

๋‚ด๊ฐ€ ํ•˜๊ณ  ์‹ถ์€ ์—๋Ÿฌ๋ฅผ ์žก๊ธฐ ์œ„ํ•ด์„œ ์–ด๋–ป๊ฒŒ ์—๋Ÿฌ๋ฅผ ์žก์„ ๊ฒƒ์ธ์ง€ ํ•˜๋‚˜ํ•˜๋‚˜ ๋ช…๋ นํ•ด์„œ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด์ฃ . ํ•˜์ง€๋งŒ React์—์„œ๋Š” ์„ ์–ธ์ ์ธ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์ง€ํ–ฅํ•ฉ๋‹ˆ๋‹ค. ์–ด๋–ป๊ฒŒ ํ•  ๊ฒƒ์ธ์ง€ ์•„๋‹Œ ๋ฌด์—‡์„ ํ• ๊ฒƒ ์ธ์ง€ ๋ง์ด์ฃ .

๊ทธ๋ž˜์„œ React์—์„œ๋Š” ์„ ์–ธ์ ์œผ๋กœ ์—๋Ÿฌ์ฒ˜๋ฆฌ๋ฅผ ๋” ์ž˜ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ๋ฐ”๋กœ React 16์—์„œ ๋„์ž…๋œ ErrorBoundary์ธ๋ฐ์š”. ์ž์‹์˜ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ผ์–ด๋‚œ ์—๋Ÿฌ๋ฅผ ๊ฐ์ง€ํ•ด์„œ ์ƒˆ๋กœ์šด ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ์—ญํ• ์„ ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ์ž…๋‹ˆ๋‹ค.

<ErrorBoundary>
  <MyComponent />
</ErrorBoundary>

๋˜๊ฒŒ ๊ฐ„๋‹จํ•˜์ฃ ? ๋‚˜๋Š” ์—๋Ÿฌ๋ฅผ ์žก๊ธฐ ์œ„ํ•ด์„œ ErrorBoundary๋ฅผ ์‚ฌ์šฉํ•  ๊ฑฐ์•ผ๋ผ๊ณ  ์„ ์–ธํ•ด ์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

๋‹จ์ ์œผ๋กœ๋Š” class ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

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;
  }
}

functional component์™€ ๋‹ค๋ฅด๊ฒŒ class component์—์„œ๋Š” ๋žœ๋”๋ง ์ฃผ๊ธฐ๋ฅผ ์ „๋ถ€ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. React์—์„œ class component์—์„œ functional component๋กœ ๋ฐ”๊พธ๋ฉด์„œ ๋ชจ๋“  ๋žœ๋”๋ง ์ฃผ๊ธฐ์— ๋Œ€ํ•ด ๋Œ€์‘ํ•˜์ง€ ๋ชปํ–ˆ๋Š”๋ฐ ์ด ErrorBoundary์˜ ํ•ต์‹ฌ์ ์ธ ๋žœ๋”๋ง ์ฃผ๊ธฐ๊ฐ€ ๋ฐ”๋กœ ์ด ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

1

๋Œ€์‹ ์— react-error-boundary๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋‚ด ํ”„๋กœ์ ํŠธ ๋‚ด์— class ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ฒŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ„๋‹จํ•œ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ๋•Œ ์„ค์ •ํ•œ FallbackComponent๋กœ ์ „ํ™˜์ด ๋ฉ๋‹ˆ๋‹ค.

function ErrorFallback({ error, resetErrorBoundary }) {
  return (
    <div role="alert">
      <p>Something went wrong:</p>
      <pre>{error.message}</pre>
      <button onClick={resetErrorBoundary}>Try again</button>
    </div>
  );
}

function MyComponent() {
  return (
    <ErrorBoundary
      FallbackComponent={ErrorFallback}
      // ์—๋Ÿฌ๋ฅผ ๊ฐ์ง“ ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณด์—ฌ์คŒ
      onReset={() => {
        // reset the state of your app so the error doesn't happen again
      }}
    >
      <ComponentThatMayThrowError />
    </ErrorBoundary>
  );
}

resetErrorBoundary๋ฅผ ์ด์šฉํ•ด์„œ ์ปดํฌ๋„ŒํŠธ์˜ api ์žฌ ํ˜ธ์ถœ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

const RetryComponent = ({ error, resetErrorBoundary }: FallbackProps) => {
  return (
    <div>
      ๋‹ค์‹œ ์‹œ๋„ํ•ด ์ฃผ์„ธ์š”
      <button onClick={resetErrorBoundary}>Retry</button>
    </div>
  );
};

const APILocalErrorBoundary: React.FC<PropsWithChildren> = ({ children }) => {
  const { reset } = useQueryErrorResetBoundary();
  // react-query์˜ hook

  return (
    <ErrorBoundary fallbackRender={RetryComponent} onReset={reset}>
      {children}
    </ErrorBoundary>
  );
};

ํ•˜์ง€๋งŒ ํ•ด๋‹น react-error-boundary๋Š” ๋งŒ๋Šฅ์ด ์•„๋‹Œ๋ฐ์š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‚ด์šฉ์€ ํฌ์ฐฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

2

์ฆ‰ ์ด๊ฑธ ๊ฑฐ๊พธ๋กœ ์ƒ๊ฐํ•ด ๋ณด๋ฉด React์˜ ์ƒ๋ช… ์ฃผ๊ธฐ ์ด์™ธ์˜ ๊ฒƒ๋“ค์€ ํฌ์ฐฉํ•˜์ง€ ๋ชปํ•œ๋‹ค๋Š” ๊ฒƒ์ด์ฃ . ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— JS์—์„œ ์ง€์›ํ•˜๋Š” try catch์™€๋Š” ์กฐ๊ธˆ ๋‹ค๋ฅธ ํŠน์ง•์„ ์ง€๋…”์Šต๋‹ˆ๋‹ค.

๋งŒ์•ฝ์— ๋‚ด๊ฐ€ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์— ๋Œ€ํ•œ ๋‚ด์šฉ์„ error boundary๋กœ ์žก๊ณ  ์‹ถ๋‹ค๋ฉด React ์ƒ๋ช…์ฃผ๊ธฐ์— ์ด๋ฅผ ํฌํ•จํ•˜๋Š” ์ž‘์—…์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋‹จ์—์„œ ์ง€์›ํ•  ์ˆ˜๋„ ์žˆ๊ณ (React-query์˜ throwOnError ์˜ต์…˜) ์•„๋‹ˆ๋ฉด ์ง์ ‘ error์— ๊ด€๋ จ๋œ state๋ฅผ ๋งŒ๋“ค์–ด์„œ ๊ฐ•์ œ๋กœ React ์‚ฌ์ดํด์— ์ง‘์–ด๋„ฃ์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

errorBoundary ์ž์„ธํžˆ ๋ณด๊ธฐ

errorBoundary๋ฅผ ์ž‘์„ฑํ•˜๋˜ ์ค‘ ํ•˜๋‚˜์˜ ์ด์Šˆ๋ฅผ ๋งŒ๋‚ฌ๋Š”๋ฐ์š” ์ €๋Š” ๋ถ„๋ช…ํžˆ ErrorBoundary๋กœ ๊ฐ์‹ธ์„œ ์—๋Ÿฌ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ์ง€๋งŒ development ํ™˜๊ฒฝ์—์„œ ์ž„์˜์˜ ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ ์‹œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•ธ๋“ค๋ง๋˜์ง€ ์•Š๋Š” ์—๋Ÿฌ๋กœ ์ •์˜๊ฐ€ ๋œ๋‹ค๋Š” ์ ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

3

์—ฌ๊ธฐ์„œ ์ €๋Š” ์‹ค์ œ๋กœ ์—๋Ÿฌ๊ฐ€ ํ•ธ๋“ค๋ง๋˜์ง€ ์•Š์•„์„œ ํ„ฐ์ง„ ๋ฌธ์ œ๋ผ ํŒ๋‹จํ•˜์˜€๊ณ  ์—ฌ๊ธฐ์„œ ErrorBoundary๋Š” ํฌ์ฐฉ๋งŒ ํ•˜๊ณ  ์‹ค์ œ ์—๋Ÿฌ๋Š” ํ•ด๊ฒฐํ•˜์ง€ ๋ชปํ•œ ์ค„ ์•Œ์•˜์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋นŒ๋“œ ํ•ด์„œ ์‹คํ–‰์„ ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์—๋Ÿฌ ํฌ์ฐฉ์€ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด๋Š” React์˜ ์—๋Ÿฌ ๋””๋ฒ„๊ฑฐ ๋•Œ๋ฌธ์— ์ƒ๊ธด ๋ฌธ์ œ์˜€๋Š”๋ฐ์š”. ์‚ฌ์šฉํ•œ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” webpack dev server๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์—ˆ๊ณ  webpack ๋‚ด์˜ debug tool์ด ์‚ฌ์ง„๊ณผ ๊ฐ™์ด ์—๋Ÿฌ๋ฅผ ์ถ”์ ํ•ด ์ฃผ๋Š” ์—ญํ• ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ErrorBoundary๋ฅผ ์ด์šฉํ•˜๋ฉด ์„œ๋น„์Šค์—์„œ๋Š” ์—๋Ÿฌ๋ฅผ ์บ์น˜ํ–ˆ์ง€๋งŒ debug ํˆด์€ ํ•ด๋‹น ์—๋Ÿฌ๋ฅผ ์บ์น˜ํ–ˆ๋Š”์ง€ ๋ชปํ–ˆ๋Š”์ง€ ๋ชจ๋ฅด๋Š” ์ƒํƒœ๋ผ๊ณ  ์ถ”์ธกํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ญ๊ฐ€ ๋‹ค๋ฅด๊ธธ๋ž˜?

์ด๋Š” JS์—์„œ ์ฒ˜๋ฆฌํ•˜๋Š” try catch์™€ error boundary๊ฐ€ ์—๋Ÿฌ์ฒ˜๋ฆฌ ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ๋˜‘๊ฐ™์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ƒ๊ธฐ๋Š” ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค.

https://github.com/facebook/create-react-app/issues/6530

Why are Error Boundaries not triggered for event handlers? ยท Issue #11409 ยท facebook/react

์ด ๋‹ต๋ณ€์€ CRA๋ ˆํฌ์ง€ํ† ๋ฆฌ ๋‚ด์—์„œ ์ด์— ๋Œ€ํ•œ ๋ฌธ์ œ์˜ ๋‹ต์„ ํ•ด ์ฃผ์—ˆ๋Š”๋ฐ์š”. ๊ฐ„๋‹จํžˆ ์ด์•ผ๊ธฐํ•˜๋ฉด React ๋ฉ”์ปค๋‹ˆ์ฆ˜์—์„œ ErrorBoundary๋กœ ์žกํžŒ ์˜ค๋ฅ˜์™€ ์žกํžˆ์ง€ ์•Š๋Š” ์˜ค๋ฅ˜๋ฅผ ๊ตฌ๋ณ„ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์—†๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ’ก ์ถ”๋ก  ์ฃผ์˜) ํ•ด๋‹น ๋‚ด์šฉ์€ ์ฝ”๋“œ๋ฅผ ๋‹จํŽธ์ ์œผ๋กœ ๋ณธ ์ถ”๋ก ์œผ๋กœ์จ ์‹ค์ œ ๋‚ด์šฉ๊ณผ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!! ์ฃผ์˜ํ•ด์„œ ๋ด์ฃผ์„ธ์š”

์ œ ์ž„์˜๋Œ€๋กœ ํ•œ๋ฒˆ React ์ฝ”๋“œ ๋‚ด๋ถ€์— ์—๋Ÿฌ๋ฅผ ์ „ํŒŒํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ๊นŒ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

function throwAndUnwindWorkLoop(unitOfWork: Fiber, thrownValue: mixed) {
  // This is a fork of performUnitOfWork specifcally for unwinding a fiber
  // that threw an exception.
  //
  // Return to the normal work loop. This will unwind the stack, and potentially
  // result in showing a fallback.
  resetSuspendedWorkLoopOnUnwind(unitOfWork);

  const returnFiber = unitOfWork.return;
  if (returnFiber === null || workInProgressRoot === null) {
    // Expected to be working on a non-root fiber. This is a fatal error
    // because there's no ancestor that can handle it; the root is
    // supposed to capture all errors that weren't caught by an error
    // boundary.
    workInProgressRootExitStatus = RootFatalErrored;
    workInProgressRootFatalError = thrownValue;
    // Set `workInProgress` to null. This represents advancing to the next
    // sibling, or the parent if there are no siblings. But since the root
    // has no siblings nor a parent, we set it to null. Usually this is
    // handled by `completeUnitOfWork` or `unwindWork`, but since we're
    // intentionally not calling those, we need set it here.
    // TODO: Consider calling `unwindWork` to pop the contexts.
    workInProgress = null;
    return;
  }

  try {
    // Find and mark the nearest Suspense or error boundary that can handle
    // this "exception".
    throwException(
      workInProgressRoot,
      returnFiber,
      unitOfWork,
      thrownValue,
      workInProgressRootRenderLanes
    );
  } catch (error) {
    // We had trouble processing the error. An example of this happening is
    // when accessing the `componentDidCatch` property of an error boundary
    // throws an error. A weird edge case. There's a regression test for this.
    // To prevent an infinite loop, bubble the error up to the next parent.
    workInProgress = returnFiber;
    throw error;
  }

  if (unitOfWork.flags & Incomplete) {
    // Unwind the stack until we reach the nearest boundary.
    unwindUnitOfWork(unitOfWork);
  } else {
    // Although the fiber suspended, we're intentionally going to commit it in
    // an inconsistent state. We can do this safely in cases where we know the
    // inconsistent tree will be hidden.
    //
    // This currently only applies to Legacy Suspense implementation, but we may
    // port a version of this to concurrent roots, too, when performing a
    // synchronous render. Because that will allow us to mutate the tree as we
    // go instead of buffering mutations until the end. Though it's unclear if
    // this particular path is how that would be implemented.
    completeUnitOfWork(unitOfWork);
  }
}

ํ•ด๋‹น ์ฝ”๋“œ ์กฐ๊ฐ์€ Fiber์—์„œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„๋•Œ ์‹คํ–‰ํ•˜๋Š” ์ฝ”๋“œ๋กœ ์ถ”์ธกํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ๋ด์•ผ ํ•˜๋Š” ๊ฑด throwException์ธ๋ฐ์š” ErrorBoundary ์ž์‹์—์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ์—์„œ ๋งŒ์•ฝ error๊ฐ€ ์ผ์–ด๋‚ฌ๋‹ค๋ฉด ์ด๋Š” ์ปดํฌ๋„ŒํŠธ์—์„œ ์ผ์–ด๋‚œ ์—๋Ÿฌ ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋Š” ํ˜„์žฌ ๋ณด์ด๋Š” Fiber์—์„œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค๋Š” ์ฆ๊ฑฐ๊ณ  ๊ทธ์— ๋Œ€ํ•œ ๋‚ด์šฉ์œผ๋กœ ํ•ด๋‹น ์ฝ”๋“œ์™€ throwException์„ ํ†ตํ•ด ์ƒ์œ„์— ์žˆ๋Š” ErrorBoundary๋ฅผ ์ฐพ์„ ๊ฒƒ์ด์ฃ .

์—ฌ๊ธฐ์„œ ๋ด์•ผ ํ•  ์ ์ด ๋ฐ”๋กœ throw error๋กœ ์‹ค์ œ ์—๋Ÿฌ๋ฅผ ๋˜์ง€๋Š” ๊ฒŒ ์•„๋‹Œ JS ์ฝ”๋“œ๋กœ ์—๋Ÿฌ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๋ณ€์ˆ˜๋กœ ์ง€์ •ํ•ด ์ฃผ๊ณ  ์žˆ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค.

throwException์—์„œ ์ฝ”๋“œ์˜ ์ผ๋ถ€๋ถ„์„ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

do {
  switch (workInProgress.tag) {
    case HostRoot: {
      const errorInfo = value;
      workInProgress.flags |= ShouldCapture;
      const lane = pickArbitraryLane(rootRenderLanes);
      workInProgress.lanes = mergeLanes(workInProgress.lanes, lane);
      const update = createRootErrorUpdate(workInProgress, errorInfo, lane);
      enqueueCapturedUpdate(workInProgress, update);
      return;
    }
    case ClassComponent:
      // Capture and retry
      const errorInfo = value;
      const ctor = workInProgress.type;
      const instance = workInProgress.stateNode;
      if (
        (workInProgress.flags & DidCapture) === NoFlags &&
        (typeof ctor.getDerivedStateFromError === "function" ||
          (instance !== null &&
            typeof instance.componentDidCatch === "function" &&
            !isAlreadyFailedLegacyErrorBoundary(instance)))
      ) {
        workInProgress.flags |= ShouldCapture;
        const lane = pickArbitraryLane(rootRenderLanes);
        workInProgress.lanes = mergeLanes(workInProgress.lanes, lane);
        // Schedule the error boundary to re-render using updated state
        const update = createClassErrorUpdate(workInProgress, errorInfo, lane);
        enqueueCapturedUpdate(workInProgress, update);
        return;
      }
      break;
    default:
      break;
  }
  // $FlowFixMe[incompatible-type] we bail out when we get a null
  workInProgress = workInProgress.return;
} while (workInProgress !== null);

์•„๊นŒ ErrorBoundary๋Š” class component๋ผ๊ณ  ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ํ•ด๋‹น case๋กœ ๋“ค์–ด๊ฐˆ ๊ฒƒ์œผ๋กœ ์ถ”์ธก์ด ๋˜๊ณ  error๋ฅผ ๋ณ€์ˆ˜๋กœ ํ• ๋‹นํ•ด์„œ ๋ญ”์ง€๋Š” ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ enqueue์— ํ•ด๋‹น ์—๋Ÿฌ๋ฅผ ์—…๋ฐ์ดํŠธ์‹œํ‚ค๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ React์—์„œ๋Š” ์—๋Ÿฌ๋ฅผ JS ๋ณ€์ˆ˜๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์–ด๋–ค ๊ฒƒ์ด ํ•ธ๋“ค๋ง ๋œ ์—๋Ÿฌ์ธ์ง€ ์•ˆ๋œ ์—๋Ÿฌ์ธ์ง€ ์•Œ ์ˆ˜ ์—†๋‹ค๊ณ  ์ถ”์ธกํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๋ก 

ErrorBoundary๋ฅผ ์ด์šฉํ•˜๋ฉด ์„ ์–ธ์ ์œผ๋กœ ์—๋Ÿฌ ํ•ธ๋“ค๋ง์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ErrorBoundary๋Š” try/catch์™€ ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ์ฃผ์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์—๋Ÿฌํ•ธ๋“ค๋ง์€ ๋ฌด์กฐ๊ฑด Errorboundary ์‚ฌ์šฉ์ด ์•„๋‹Œ ์ƒํ™ฉ์— ๋งž๊ฒŒ ์‚ฌ์šฉํ•ด์•ผ๊ฒ ์ฃ . ์ œ ํ”„๋กœ์ ํŠธ ๊ฐ™์€ ๊ฒฝ์šฐ์—๋Š” ErrorBoundary๋Š” ์–ด์ฉ” ์ˆ˜ ์—†์ด ์—๋Ÿฌ ํŽ˜์ด์ง€๋ฅผ ๋ณด์—ฌ์ฃผ์–ด์•ผ ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ณ  ๊ทธ ์ด์™ธ์—๋Š” axios๋‚˜ ๋‹ค๋ฅธ ๊ณ„์ธต์œผ๋กœ ๋ถ„๋ฆฌํ•ด์„œ ์‚ฌ์šฉ ์ค‘์ž…๋‹ˆ๋‹ค. ๋‹ค์Œ ํฌ์ŠคํŒ…์—์„œ ํ•œ๋ฒˆ ์ž‘์„ฑํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

ยฉ 2024 Adultlee. All rights reserved.Made with โค by ์ด์„ฑ์ธ