July 27, 2025

๐Ÿ“‰ Silent Failures: ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ ์—๋Ÿฌ ๋ชจ๋‹ˆํ„ฐ๋ง ๋ถ€์žฌ

JavaScript
UX
์—๋Ÿฌ์ฒ˜๋ฆฌ
์•„ํ‚คํ…์ฒ˜

Summary

ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ ์—๋Ÿฌ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ์˜ ๋ถ€์žฌ๋Š” ์‚ฌ์šฉ์ž ๊ฒฝํ—˜ ์ €ํ•˜, ์œ ์ง€๋ณด์ˆ˜ ๋ณต์žก์„ฑ ์ฆ๊ฐ€, ๋น„์ฆˆ๋‹ˆ์Šค ์†์‹ค ๋“ฑ ์‹ฌ๊ฐํ•œ ๋ฌธ์ œ๋ฅผ ์ดˆ๋ž˜ํ•ฉ๋‹ˆ๋‹ค. window.onerror, unhandledrejection๊ณผ ๊ฐ™์€ ์ „์—ญ ์—๋Ÿฌ ํ•ธ๋“ค๋Ÿฌ์™€ Sentry์™€ ๊ฐ™์€ ์ „๋ฌธ ์—๋Ÿฌ ๋ชจ๋‹ˆํ„ฐ๋ง ์„œ๋น„์Šค๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์—๋Ÿฌ๋ฅผ ์„ ์ œ์ ์œผ๋กœ ๊ฐ์ง€ํ•˜๊ณ  ํ•ด๊ฒฐํ•จ์œผ๋กœ์จ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์•ˆ์ •์„ฑ๊ณผ ์‚ฌ์šฉ์ž ๋งŒ์กฑ๋„๋ฅผ ํฌ๊ฒŒ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Why Wrong?

์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์‚ฌ์šฉ์ž ๊ธฐ๊ธฐ, ๋„คํŠธ์›Œํฌ ํ™˜๊ฒฝ, ๋ธŒ๋ผ์šฐ์ € ๋ฒ„์ „ ๋“ฑ ์˜ˆ์ธก ๋ถˆ๊ฐ€๋Šฅํ•œ ๋‹ค์–‘ํ•œ ํ™˜๊ฒฝ์—์„œ ์‹คํ–‰๋˜๋ฏ€๋กœ, ๊ฐœ๋ฐœ์ž๊ฐ€ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ ์—๋Ÿฌ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ์ด ๋ถ€์žฌํ•˜๋ฉด, ์‚ฌ์šฉ์ž๋“ค์€ ๋ถˆํŽธ์„ ๊ฒช๊ฑฐ๋‚˜ ๊ธฐ๋Šฅ ์˜ค์ž‘๋™์„ ๊ฒฝํ—˜ํ•ด๋„ ๊ฐœ๋ฐœ์ž๋Š” ์ด๋Ÿฌํ•œ ๋ฌธ์ œ ๋ฐœ์ƒ ์—ฌ๋ถ€๋ฅผ ์•Œ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์น˜๋ช…์ ์ธ ๋ฌธ์ œ๋ฅผ ์•ผ๊ธฐํ•ฉ๋‹ˆ๋‹ค:

  • ์‚ฌ์šฉ์ž ๊ฒฝํ—˜ ์ €ํ•˜: ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ด๋„ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ ์ ˆํ•œ ํ”ผ๋“œ๋ฐฑ(์˜ˆ: ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€, ๋Œ€์ฒด UI)์„ ์ œ๊ณตํ•˜์ง€ ๋ชปํ•˜๊ณ , ๊ธฐ๋Šฅ์ด ์กฐ์šฉํžˆ ์‹คํŒจํ•˜๊ฑฐ๋‚˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋ฉˆ์ถ”๋Š” ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•˜์—ฌ ์‚ฌ์šฉ์ž ๋งŒ์กฑ๋„๊ฐ€ ํฌ๊ฒŒ ๋–จ์–ด์ง‘๋‹ˆ๋‹ค.
  • ์ƒ์‚ฐ์„ฑ ๋ฐ ์œ ์ง€๋ณด์ˆ˜์„ฑ ์ €ํ•ด: ๋ฌธ์ œ ๋ฐœ์ƒ ์‹œ ๊ฐœ๋ฐœ์ž๋Š” ์žฌํ˜„ํ•˜๊ธฐ ์–ด๋ ต๊ณ , ์›์ธ์„ ํŒŒ์•…ํ•˜๊ธฐ ์œ„ํ•œ ๋””๋ฒ„๊น…์— ๋ง‰๋Œ€ํ•œ ์‹œ๊ฐ„์„ ์†Œ๋ชจํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋ฒ„๊ทธ ์ˆ˜์ • ์ฃผ๊ธฐ๋ฅผ ๋Š˜๋ฆฌ๊ณ  ๊ฐœ๋ฐœ ํšจ์œจ์„ ๋–จ์–ด๋œจ๋ฆฝ๋‹ˆ๋‹ค.
  • ๋ฐ์ดํ„ฐ ์†์‹ค ๋ฐ ๋ณด์•ˆ ์œ„ํ—˜: ์ค‘์š”ํ•œ ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ๊ฐ€ ์œ ์‹ค๋˜๊ฑฐ๋‚˜, ํŠน์ • ์—๋Ÿฌ๊ฐ€ ์ž ์žฌ์ ์ธ ๋ณด์•ˆ ์ทจ์•ฝ์ ์˜ ์‹ ํ˜ธ์ผ ์ˆ˜ ์žˆ์Œ์—๋„ ์ด๋ฅผ ์ธ์ง€ํ•˜์ง€ ๋ชปํ•˜์—ฌ ๋” ํฐ ๋ฌธ์ œ๋กœ ์ด์–ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋น„์ฆˆ๋‹ˆ์Šค ์†์‹ค: ํ•ต์‹ฌ ๊ธฐ๋Šฅ์˜ ์˜ค๋ฅ˜๋Š” ์ง์ ‘์ ์ธ ๋งค์ถœ ์†์‹ค์ด๋‚˜ ์‚ฌ์šฉ์ž ์ดํƒˆ๋กœ ์ด์–ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—๋Ÿฌ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถ„์„ํ•˜์—ฌ ์„œ๋น„์Šค ์•ˆ์ •์„ฑ์„ ๊ฐœ์„ ํ•˜๋Š” ๊ธฐํšŒ๋ฅผ ์ƒ์‹คํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

How to Fix?

ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ ์—๋Ÿฌ๋ฅผ ์„ ์ œ์ ์œผ๋กœ ๊ฐ์ง€ํ•˜๊ณ  ๋Œ€์‘ํ•˜๊ธฐ ์œ„ํ•œ ์ฒด๊ณ„์ ์ธ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ์„ ๊ตฌ์ถ•ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ ๋ฐฉ๋ฒ•๋“ค์„ ๊ณ ๋ คํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

  1. ์ „์—ญ ์—๋Ÿฌ ํ•ธ๋“ค๋Ÿฌ ๊ตฌํ˜„: ๋ธŒ๋ผ์šฐ์ €์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์บ์น˜๋˜์ง€ ์•Š์€(uncaught) JavaScript ์—๋Ÿฌ์™€ Promise ๊ฑฐ๋ถ€๋ฅผ ์ „์—ญ์ ์œผ๋กœ ๊ฐ์ง€ํ•ฉ๋‹ˆ๋‹ค.
    • window.onerror: ๋™๊ธฐ์ ์œผ๋กœ ๋ฐœ์ƒํ•˜๋Š” ์บ์น˜๋˜์ง€ ์•Š์€ ์Šคํฌ๋ฆฝํŠธ ์—๋Ÿฌ๋ฅผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
    • window.addEventListener('unhandledrejection'): ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋ฐœ์ƒํ•˜๋Š”, ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์€ Promise ๊ฑฐ๋ถ€๋ฅผ ๊ฐ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  2. ์ „์šฉ ์—๋Ÿฌ ๋ชจ๋‹ˆํ„ฐ๋ง ์„œ๋น„์Šค ํ™œ์šฉ: Sentry, Bugsnag, New Relic, Datadog ๋“ฑ ์ „๋ฌธ ์—๋Ÿฌ ๋ชจ๋‹ˆํ„ฐ๋ง ์†”๋ฃจ์…˜์„ ๋„์ž…ํ•ฉ๋‹ˆ๋‹ค. ์ด ์„œ๋น„์Šค๋“ค์€ ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ ์ฝœ ์Šคํƒ, ๋ธŒ๋ผ์šฐ์ € ์ •๋ณด, ์‚ฌ์šฉ์ž ์ •๋ณด, ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๋“ฑ ํ’๋ถ€ํ•œ ์ปจํ…์ŠคํŠธ ๋ฐ์ดํ„ฐ๋ฅผ ์ž๋™์œผ๋กœ ์ˆ˜์ง‘ํ•˜์—ฌ ๊ฐœ๋ฐœ์ž์—๊ฒŒ ๋ณด๊ณ ํ•˜๊ณ , ์—๋Ÿฌ ํŠธ๋ Œ๋“œ ๋ถ„์„ ๋ฐ ์•Œ๋ฆผ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜์—ฌ ํšจ์œจ์ ์ธ ๋ฌธ์ œ ํ•ด๊ฒฐ์„ ๋•์Šต๋‹ˆ๋‹ค.
  3. React Error Boundaries (React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๊ฒฝ์šฐ): React ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ ๋‚ด์—์„œ ๋ฐœ์ƒํ•˜๋Š” JavaScript ์—๋Ÿฌ๋ฅผ ์บ์น˜ํ•˜๊ณ , ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ ์ปดํฌ๋„ŒํŠธ ๋Œ€์‹  ํด๋ฐฑ(fallback) UI๋ฅผ ๋ Œ๋”๋งํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์ฒด๊ฐ€ ๋ง๊ฐ€์ง€๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค. componentDidCatch ๋ผ์ดํ”„์‚ฌ์ดํด ๋ฉ”์„œ๋“œ ๋˜๋Š” static getDerivedStateFromError๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ, ์ด๊ณณ์—์„œ ์ „์—ญ ์—๋Ÿฌ ๋ชจ๋‹ˆํ„ฐ๋ง ์„œ๋น„์Šค๋กœ ์—๋Ÿฌ๋ฅผ ์ „์†กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  4. ๋กœ๊ทธ ๋ฐ ์ปจํ…์ŠคํŠธ ๊ฐ•ํ™”: ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ ์ถฉ๋ถ„ํ•œ ๋กœ๊ทธ ์ •๋ณด(์‚ฌ์šฉ์ž ID, ํŽ˜์ด์ง€ ๊ฒฝ๋กœ, ์•ก์…˜ ๊ธฐ๋ก ๋“ฑ)๋ฅผ ํ•จ๊ป˜ ์ „์†กํ•˜์—ฌ ์—๋Ÿฌ ๋ฐœ์ƒ ์ƒํ™ฉ์„ ์žฌ๊ตฌ์„ฑํ•˜๊ณ  ์›์ธ์„ ๋น ๋ฅด๊ฒŒ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
  5. ๊ฐœ๋ฐœ ๋‹จ๊ณ„์—์„œ์˜ ์—๋Ÿฌ ๊ฒ€์ถœ ๊ฐ•ํ™”: ESLint, TypeScript ๋“ฑ์„ ํ™œ์šฉํ•˜์—ฌ ๊ฐœ๋ฐœ ๋‹จ๊ณ„์—์„œ ์ž ์žฌ์ ์ธ ์—๋Ÿฌ๋ฅผ ์ค„์ด๊ณ , ์ฒ ์ €ํ•œ ํ…Œ์ŠคํŠธ(๋‹จ์œ„ ํ…Œ์ŠคํŠธ, ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ, E2E ํ…Œ์ŠคํŠธ)๋ฅผ ํ†ตํ•ด ์—๋Ÿฌ๊ฐ€ ํ”„๋กœ๋•์…˜์— ๋ฐฐํฌ๋˜๊ธฐ ์ „์— ๋ฐœ๊ฒฌ๋  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

Before Code (Bad)

// index.js ๋˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ง„์ž…์ 

console.log("์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘.");

function fetchData() {
  // ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ์ฝ”๋“œ
  // ์˜๋„์น˜ ์•Š๊ฒŒ null์ด ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.
  const config = null; 
  
  // config๊ฐ€ null์ผ ๋•Œ ์†์„ฑ์— ์ ‘๊ทผํ•˜๋ฉด TypeError๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
  // ์ด ์—๋Ÿฌ๋Š” ์ „์—ญ์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์œผ๋ฉด ๋ธŒ๋ผ์šฐ์ € ์ฝ˜์†”์—๋งŒ ํ‘œ์‹œ๋˜๊ณ , ๊ฐœ๋ฐœ์ž๋Š” ์•Œ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  console.log(config.apiUrl); // Uncaught TypeError: Cannot read properties of null (reading 'apiUrl')
}

function performAsyncTask() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            // ๋น„๋™๊ธฐ ์ž‘์—… ์ค‘ ์‹คํŒจ๊ฐ€ ๋ฐœ์ƒํ–ˆ์ง€๋งŒ, catch()๋กœ ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ
            reject(new Error("๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ ์‹คํŒจ!")); // Unhandled Promise Rejection
        }, 500);
    });
}

// ํŽ˜์ด์ง€ ๋กœ๋“œ ํ›„ ํŠน์ • ์‹œ์ ์— ์‹คํ–‰๋˜๋Š” ํ•จ์ˆ˜๋“ค
setTimeout(fetchData, 1000);
performAsyncTask();

console.log("์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‹คํ–‰ ์ค‘์ž…๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ด๋„ ๊ฐœ๋ฐœ์ž๋Š” ์•Œ๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.");

After Code (Good)

// index.js ๋˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ง„์ž…์ 

console.log("์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘.");

// 1. ์ „์—ญ JavaScript ์—๋Ÿฌ ํ•ธ๋“ค๋Ÿฌ (๋™๊ธฐ ์—๋Ÿฌ ์ฒ˜๋ฆฌ)
// 'message', 'source', 'lineno', 'colno', 'error' ๊ฐ์ฒด๋ฅผ ์ธ์ž๋กœ ๋ฐ›์Šต๋‹ˆ๋‹ค.
window.onerror = function(message, source, lineno, colno, error) {
  console.error('--- ์ „์—ญ JS ์—๋Ÿฌ ๊ฐ์ง€ (window.onerror) ---');
  console.error('๋ฉ”์‹œ์ง€:', message);
  console.error('์†Œ์Šค:', source);
  console.error('์œ„์น˜:', lineno, '์ค„,', colno, '์ปฌ๋Ÿผ');
  console.error('์—๋Ÿฌ ๊ฐ์ฒด:', error); // ์—๋Ÿฌ ์Šคํƒ ํŠธ๋ ˆ์ด์Šค ๋“ฑ ์ƒ์„ธ ์ •๋ณด
  
  // ์—ฌ๊ธฐ์— ์‹ค์ œ ์—๋Ÿฌ ๋ชจ๋‹ˆํ„ฐ๋ง ์„œ๋น„์Šค(์˜ˆ: Sentry.captureException(error))๋กœ ์—๋Ÿฌ๋ฅผ ์ „์†กํ•˜๋Š” ๋กœ์ง ์ถ”๊ฐ€
  
  // true๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด ๋ธŒ๋ผ์šฐ์ €์˜ ๊ธฐ๋ณธ ์—๋Ÿฌ ์ฒ˜๋ฆฌ(์ฝ˜์†” ์ถœ๋ ฅ, ์—๋Ÿฌ ์‹ฌ๋ณผ ํ‘œ์‹œ ๋“ฑ)๋ฅผ ๋ง‰์Šต๋‹ˆ๋‹ค.
  return true; 
};

// 2. ์ „์—ญ Unhandled Promise Rejection ํ•ธ๋“ค๋Ÿฌ (๋น„๋™๊ธฐ ์—๋Ÿฌ ์ฒ˜๋ฆฌ)
// 'event' ๊ฐ์ฒด๋Š” 'reason' ์†์„ฑ์„ ํ†ตํ•ด ๊ฑฐ๋ถ€๋œ Promise์˜ ๊ฐ’์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค.
window.addEventListener('unhandledrejection', function(event) {
  console.error('--- ์ „์—ญ Promise ๊ฑฐ๋ถ€ ๊ฐ์ง€ (unhandledrejection) ---');
  console.error('๊ฑฐ๋ถ€ ์‚ฌ์œ :', event.reason); // ์ฃผ๋กœ Error ๊ฐ์ฒด์ด๊ฑฐ๋‚˜ Promise.reject()๋กœ ์ „๋‹ฌ๋œ ๊ฐ’
  
  // ์—ฌ๊ธฐ์— ์‹ค์ œ ์—๋Ÿฌ ๋ชจ๋‹ˆํ„ฐ๋ง ์„œ๋น„์Šค(์˜ˆ: Sentry.captureException(event.reason))๋กœ ํ”„๋กœ๋ฏธ์Šค ๊ฑฐ๋ถ€๋ฅผ ์ „์†กํ•˜๋Š” ๋กœ์ง ์ถ”๊ฐ€
  
  // event.preventDefault()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ธŒ๋ผ์šฐ์ €์˜ ๊ธฐ๋ณธ ๋™์ž‘(์ฝ˜์†” ๊ฒฝ๊ณ )์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  event.preventDefault();
});


function fetchData() {
  const config = null; 
  console.log(config.apiUrl); // ์ด ์—๋Ÿฌ๋Š” window.onerror์— ์˜ํ•ด ๊ฐ์ง€๋ฉ๋‹ˆ๋‹ค.
}

function performAsyncTask() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject(new Error("๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ ์‹คํŒจ!")); // ์ด ๊ฑฐ๋ถ€๋Š” unhandledrejection์— ์˜ํ•ด ๊ฐ์ง€๋ฉ๋‹ˆ๋‹ค.
        }, 500);
    });
}

setTimeout(fetchData, 1000);
performAsyncTask();

console.log("์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‹คํ–‰ ์ค‘์ž…๋‹ˆ๋‹ค. ์ด์ œ ๋ฐœ์ƒํ•œ ์—๋Ÿฌ๋ฅผ ์ „์—ญ์ ์œผ๋กœ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.");

/*
React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๊ฒฝ์šฐ, ์ปดํฌ๋„ŒํŠธ ๋ Œ๋”๋ง ๋‹จ๊ณ„์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์—๋Ÿฌ๋ฅผ ์žก๊ธฐ ์œ„ํ•ด
'Error Boundary' ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŠน์ • UI ๋ถ€๋ถ„์˜ ์—๋Ÿฌ๋ฅผ ๊ฒฉ๋ฆฌํ•˜๊ณ  ํด๋ฐฑ UI๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ์‹œ:
import React from 'react';

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

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

  componentDidCatch(error, errorInfo) {
    console.error("React Error Boundary Caught:", error, errorInfo);
    // ์—ฌ๊ธฐ์— Sentry ๋“ฑ ์—๋Ÿฌ ๋ชจ๋‹ˆํ„ฐ๋ง ์„œ๋น„์Šค๋กœ ์—๋Ÿฌ๋ฅผ ์ „์†กํ•˜๋Š” ๋กœ์ง ์ถ”๊ฐ€
    this.setState({ error, errorInfo });
  }

  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
}

function App() {
  return (
    <ErrorBoundary>
      <YourPotentiallyBuggyComponent />
    </ErrorBoundary>
  );
}
*/