๐Ÿš€ Next.js 8์žฅ: Error Handling โ€” ๋‚ด ์•ฑ์„ ์ง€ํ‚ค๋Š” ์ตœํ›„์˜ ๋ฐฉ์–ด์„ 

๐Ÿ“‹ ๊ฐœ์š”

error.tsx, not-found.tsx, ErrorBoundary๋ฅผ ์กฐํ•ฉํ•ด ์•ฑ์„ ์•ˆ์ „ํ•˜๊ฒŒ ์ง€ํ‚ค๋Š” ๋ฐฉ๋ฒ•์„ ๋‹ค๋ฃน๋‹ˆ๋‹ค.

๐Ÿ“‹ ๋ชฉ์ฐจ


๐Ÿ“Œ ์ด ๋ฌธ์„œ๋ฅผ ์ฝ๊ธฐ ์ „์—

โฑ๏ธ ์˜ˆ์ƒ ์ฝ๊ธฐ ์‹œ๊ฐ„: 15๋ถ„(์ „์ฒด) / ํ•ต์‹ฌ ํŒŒํŠธ๋งŒ: 8๋ถ„

๐Ÿ—บ๏ธ ์ด ๋ฌธ์„œ์˜ ํ๋ฆ„
RSC ์—๋Ÿฌ ํญ๋ฐœ์˜ ์œ„ํ—˜์„ฑ โ†’ error.tsx ๋ฐฉ์–ด๋ง‰ ์›๋ฆฌ โ†’ ์—๋Ÿฌ๋ฅผ ์ž˜๊ฒŒ ๋ถ€์ˆ˜์–ด ๊ฒฉ๋ฆฌํ•˜๋Š” ์‹œ๋‹ˆ์–ด ์•„ํ‚คํ…์ฒ˜

๐ŸŽฏ ์ด ๋ฌธ์„œ๋ฅผ ๋‹ค ์ฝ์œผ๋ฉด ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ

  • try-catch ๋กœ๋งŒ ๋–ก์น ํ•˜๋˜ ํ•˜์ˆ˜ ์ฝ”๋“œ์—์„œ ๋ฒ—์–ด๋‚˜, ์„ ์–ธํ˜• ์ง€์‹œ์ž ํŒŒ์ผ(error.tsx) ํ•˜๋‚˜๋กœ ํด๋” ๋‹จ์œ„ ์—๋Ÿฌ๋ฅผ ์šฐ์•„ํ•˜๊ฒŒ ์ œ์••ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์—๋Ÿฌ๊ฐ€ ๋‚œ ๊ณณ๋งŒ ๋ฒ„ํŠผ์œผ๋กœ reset() ํ•จ์ˆ˜๋ฅผ ๋ถˆ๋ ค ํŽ˜์ด์ง€ ๊ฐ•์ œ ์ƒˆ๋กœ๊ณ ์นจ ์—†์ด ํ•ด๋‹น ํŒŒํŽธ ์ปดํฌ๋„ŒํŠธ๋งŒ ํšŒ๋ณต์‹œํ‚ค๋Š” ๊ณ ๊ธ‰ ๋ Œ๋” ์ปจํŠธ๋กค์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ—บ๏ธ ์ด ๋ฌธ์„œ์˜ ๋ฐฐ๊ฒฝ ์„ธ๊ณ„๊ด€: '์˜์ˆ˜๋„ค ์ปค๋ฎค๋‹ˆํ‹ฐ'

  • ์˜์ฒ (์ƒˆ๋กœ ์˜จ ์ฃผ๋‹ˆ์–ด): "์–ด? ์‚ฌ์ด๋“œ๋ฐ”์—์„œ ์œ ์ € ๋žญํ‚น ๊ฐ€์ ธ์˜ค๋Š” API ํ•˜๋‚˜ ํ„ฐ์กŒ๋‹ค๊ณ  ์‚ฌ์ดํŠธ ์ „์ฒด๊ฐ€ ์—„์ฒญ ๋ฌด์„œ์šด ์—๋Ÿฌ ์Šคํฌ๋ฆฐ์œผ๋กœ ๋„๋ฐฐ๋˜๋ฉด์„œ ๋ป—์–ด๋ฒ„๋ ค์š”! ๋ฉ€์ฉกํ•œ ๋‹ค๋ฅธ ๊ฒŒ์‹œํŒ ๊ธ€๋“ค๋„ ์•ˆ ๋ณด์ด๊ณ  ์™„์ „ ๋งˆ๋น„์˜ˆ์š”! ๐Ÿ˜ญ"
  • ์˜ํ˜ธ(FE ๋ฆฌ๋“œ): "์˜์ฒ  ๋‹˜... React ํŠธ๋ฆฌ๋Š” ์ปดํฌ๋„ŒํŠธ ํ•˜๋‚˜๊ฐ€ ์—๋Ÿฌ๋กœ ํ„ฐ์ง€๋ฉด ์ž๊ธฐ ๋ถ€๋ชจ ํ˜•์ œ๊นŒ์ง€ ๋‹ค ์ฃฝ๋Š” ๋™๋ฐ˜ ์ž์‚ด(?) ์˜ ๋ฒ•์น™์ด ์žˆ๋‹จ ๋ง์ด์—์š”! ๋„ฅ์ŠคํŠธ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๋ฐฉํ™”๋ฒฝ(error.tsx) ํŒŒ์ผ๋งŒ ํˆญ ๋˜์ ธ๋†จ์–ด๋„ ๋žญํ‚น ์˜์—ญ ํ•˜๋‚˜๋งŒ ์šฐ์•„ํ•˜๊ฒŒ ์ฃฝ๊ณ  ๋‹ค๋ฅธ ๊ณณ์€ ์‚ด์•˜์„ ํ…๋ฐ!"

๐Ÿค” ์™œ ์•Œ์•„์•ผ ํ•˜๋Š”๊ฐ€

์˜ค๋ž˜๋œ SPA ๋ฐฉ์‹์—์„œ๋Š” API ์—๋Ÿฌ๊ฐ€ ๋‚˜๋ฉด ์ฃผ๋กœ catch ์•ˆ์—์„œ alert("์—๋Ÿฌ์ž…๋‹ˆ๋‹ค") ๋„์šฐ๊ณ  ๋๋‚ฌ์–ด.
ํ•˜์ง€๋งŒ Next.js์˜ ๋Œ€์„ธ์ธ React Server Component(RSC) ์„ธ์ƒ์€ ์™„์ „ํžˆ ๋‹ฌ๋ผ.
์„œ๋ฒ„์—์„œ ์กฐ๋ฆฝ๋˜๋˜ HTML ์ชผ๊ฐ€๋ฆฌ๋“ค์ด await db() ํ•˜๋‹ค๊ฐ€ 1์ดˆ ๋’ค์— ํŽ‘! ํ•˜๊ณ  ํ„ฐ์ ธ๋ฒ„๋ ค(Exception Throw).

Next.js ์„œ๋ฒ„๊ฐ€ ์—๋Ÿฌ๋ฅผ ๋ฟœ์œผ๋ฉด ์ด ๋ฌด์‹œ๋ฌด์‹œํ•œ ์—๋Ÿฌ ๋ฉ์–ด๋ฆฌ๊ฐ€ ๊ฑท์žก์„ ์ˆ˜ ์—†์ด ์ƒ์œ„ ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๋กœ ์—ญ๋ฅ˜ํ•˜๋ฉฐ ์˜ฌ๋ผ๊ฐ€. ๋‹จ๋‹จํ•œ ๋šœ๊ป‘(Error Boundary)์œผ๋กœ ์–ด๋А ์ค‘๊ฐ„ ์ง€์ ์—์„œ ๋”ฑ! ๋ง‰์•„๋‚ด์ง€ ์•Š์œผ๋ฉด, ๊ฒฐ๊ตญ ์ตœ์ƒ๋‹จ ๋ฃจํŠธ ๋ ˆ์ด์•„์›ƒ๋งˆ์ € ํญํŒŒ์‹œํ‚ค๋ฉฐ ์•ฑ ์ „์ฒด๊ฐ€ ์ƒˆํ•˜์–€ "Internal Server Error" ๋ฌด๋ค ์Šคํฌ๋ฆฐ์œผ๋กœ ๋Œ๋ณ€ํ•ด.
๊ทธ ์ž‘์€ ์ฐŒ๊บผ๊ธฐ ์—๋Ÿฌ ํ•˜๋‚˜ ๋•Œ๋ฌธ์— ๋ฉ€์ฉกํ•˜๊ฒŒ ๋Œ์•„๊ฐ€๋˜ ์‚ฌ์ดํŠธ ๋ฉ”์ธ GNB์™€ ์‚ฌ์ด๋“œํƒญ๋งˆ์ € ์ฆ๋ฐœํ•ด๋ฒ„๋ฆฌ๋Š” ๊ฒƒ์€ ์ตœ์•…์˜ UX(์‚ฌ์šฉ์ž ๊ฒฝํ—˜)์•ผ.

์ด ๊ฑฐ๋Œ€ํ•œ ๋„๋ฏธ๋…ธ ๋ถ•๊ดด๋ฅผ ๋ง‰์•„๋‚ด๋Š” ๋„ฅ์ŠคํŠธ ํŒŒ์ผ ์‹œ์Šคํ…œ ์˜ˆ์•ฝ์–ด๊ฐ€ ๋ฐ”๋กœ error.tsx์•ผ.


๐Ÿ—๏ธ ๋น„์œ ๋กœ ๋จผ์ € ์ดํ•ดํ•˜๊ธฐ

๐Ÿง’ 5์‚ด์—๊ฒŒ ์„ค๋ช…ํ•œ๋‹ค๋ฉด? (์˜์ˆ˜๋„ค ๊ตญ๋ฐฅ์ง‘์˜ ๋ฐฉํ™” ์…”ํ„ฐ)

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

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


๐Ÿงฉ error.tsx์˜ ๋งˆ๋ฒ•: Error Boundary์˜ ์ง„ํ™” ๐ŸŸข

๊ธฐ์กด React ๊ฐœ๋ฐœ์ž๋“ค์ด Error Boundary ๋žฉํ•‘๊ธฐ(Class Component)๋ฅผ ์†์ˆ˜ ์งœ๋ฉฐ ๊ณ ํ†ต๋ฐ›์•˜๋‹ค๋ฉด, Next.js์—์„œ๋Š” ๊ทธ๋ƒฅ ํ„ฐ์งˆ ๊ฒƒ ๊ฐ™์€ ํด๋”์— ์ € ์ด๋ฆ„์˜ ํŒŒ์ผ์„ "๋งŒ๋“ค๊ธฐ๋งŒ ํ•˜๋ฉด" ๋ผ.

1) ๋ฐฉ์–ด๋ง‰ ๊ธฐ๋ณธ ์›๋ฆฌ

app/dashboard/ ํŽ˜์ด์ง€๊ฐ€ ํ„ฐ์ง„๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ž.

app/
 โ””โ”€ dashboard/
     โ”œโ”€ layout.tsx  (1. ์ด๋†ˆ๋งˆ์ € ํ„ฐ์ง€๋ฉด ๋” ์œ„์ชฝ์œผ๋กœ ์—ญ๋ฅ˜ํ•ด ์˜ฌ๋ผ๊ฐ€๋ฒ„๋ฆฐ๋‹ค)
     โ”œโ”€ error.tsx   (2. ๊ฐ•๋ ฅํ•œ ๋ฐฉํญ๋ฌธ! ์ด ํŒŒ์ผ์ด ์กด์žฌํ•˜๋Š” ํ•œ page.tsx์˜ ํญ๋ฐœ์€ ๋ฌธ ๋ฐ–์„ ๋‚˜๊ฐ€์ง€ ๋ชปํ•จ)
     โ””โ”€ page.tsx    (3. ์—๋Ÿฌ ์œ ๋ฐœ์ž! ๋‚ด๋ถ€์—์„œ DB ์กฐํšŒํ•˜๋‹ค ๋ป—์Œ)

๋งŒ์•ฝ ํ„ฐ์ง€๋ฉด, Next.js๊ฐ€ page.tsx UI๋ฅผ ๋ Œ๋” ๋ฐ•์Šค์—์„œ ์‹น ๋œ์–ด๋‚ด๋ฒ„๋ฆฌ๊ณ , ๊ทธ ์ž๋ฆฌ์— ๋‹ˆ๊ฐ€ error.tsx ํŒŒ์ผ์—์„œ ๋ฆฌํ„ด์‹œํ‚จ Fallback UI ์ปดํฌ๋„ŒํŠธ๋กœ ์™! ๋Œ€์ฒดํ•ด๋ฒ„๋ ค.

2) ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ ์„ ์–ธ ๊ฐ•์ œ ๊ทœ์•ฝ (use client)

โš ๏ธ ๊ฐ€์žฅ ์ดˆ๋ณด์ž๋“ค์ด ๋งŽ์ด ํ•˜๋Š” ์‹ค์ˆ˜ 1์ˆœ์œ„. error.tsx๋Š” ๋ฌด์กฐ๊ฑด ์ฒซ ์ค„์— 'use client' ์ง€์‹œ์ž ๊ฐ€ ๋‹ฌ๋ ค ์žˆ์–ด์•ผ ํ•ด.

์™œ์ผ๊นŒ? ์—๋Ÿฌ๋Š” ์–ธ์ œ ์–ด๋А ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ํ„ฐ์งˆ์ง€ ๋ชฐ๋ผ.
์„œ๋ฒ„์—์„œ HTML์„ ์กฐ๋ฆฝํ•˜๋‹ค๊ฐ€(RSC) ํ„ฐ์งˆ ์ˆ˜๋„ ์žˆ๊ณ , ๋‚ด ํฐ์—์„œ onClick ๋ˆ„๋ฅด๋‹ค ๋Ÿฐํƒ€์ž„์—(Client) ํ„ฐ์งˆ ์ˆ˜๋„ ์žˆ์ง€. ๋ชจ๋“  ์—๋Ÿฌ(Server, Client ๋ฌด๊ด€)๋ฅผ ์žก์•„์ฑ„๊ณ  ๋ธŒ๋ผ์šฐ์ € ์ฝ˜์†”์—์„œ Recovery(๋ณต๊ตฌ ๋ฒ„ํŠผ) ๋™์ž‘๊นŒ์ง€ ์ง€์›ํ•˜๋ ค๋ฉด ์ด ํŒŒ์ผ ์ž์ฒด๊ฐ€ ํด๋ผ์ด์–ธํŠธ ๋ฒ ์ด์Šค์—์„œ ๊ตฌ๋™๋˜์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด์•ผ.

// app/dashboard/error.tsx
'use client' // โค๏ธ ์žŠ์œผ๋ฉด ๋นŒ๋“œ ์—๋Ÿฌ ๋‚จ!
 
import { useEffect } from 'react'
 
export default function DashboardError({
  error,
  reset,
}: {
  error: Error & { digest?: string } // ์—๋Ÿฌ ์ •๋ณด ๊ฐ์ฒด
  reset: () => void // ํญ๋ฐœํ–ˆ๋˜ page.tsx ์˜์—ญ์„ ์žฌ๋ Œ๋”๋ง ์‹œ๋„ํ•˜๋Š” ๋งˆ๋ฒ•์˜ ๋ฒ„ํŠผ
}) {
  useEffect(() => {
    // Sentry, Datadog ๋“ฑ์œผ๋กœ ๋ชฐ๋ž˜ ์—๋Ÿฌ ์ „๋ฌธ์„ ์ˆ˜์ง‘ํ•ด ์˜ฌ๋ฆฐ๋‹ค
    console.error('์•—! ๋Œ€์‹œ๋ณด๋“œ์—์„œ ์—„์ฒญ๋‚œ ์—๋Ÿฌ๊ฐ€:', error)
  }, [error])
 
  return (
    <div className="bg-red-50 p-4 rounded-md">
      <h2>๋ญ”๊ฐ€ ๋‹จ๋‹จํžˆ ์ž˜๋ชป๋์–ด์š”. (๋ฐฉ์ˆ˜ ๊ฒฉ๋ฒฝ ๋‹ซํž˜)</h2>
      {/* ๋‹ค์‹œ ์‹œ๋„ํ•˜๊ธฐ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ, ์ปดํฌ๋„ŒํŠธ๋งŒ ๊ฐ•์ œ๋กœ ์žฌ์š”์ฒญ (์ „์ฒด ์ƒˆ๋กœ๊ณ ์นจ ๋ฌด๊ด€) */}
      <button onClick={() => reset()}>
        ๋ฌธ ๋‹ค์‹œ ํ•œ ๋ฒˆ ์—ด์–ด๋ณด๊ธฐ
      </button>
    </div>
  )
}

๐ŸŒฑ ์—๋Ÿฌ์˜ ์ง€์—ญํ™” (Localization) ์ „๋žต ๐ŸŸก

์ด์ œ ๋ฉด์ ‘ ๋‹จ๊ณจ ์งˆ๋ฌธ์ด์ž ์‹œ๋‹ˆ์–ด ์•„ํ‚คํ…์ฒ˜์˜ ํ•ต์‹ฌ ๋„๋ฉ”์ธ์œผ๋กœ ๋“ค์–ด๊ฐ€๋ณผ๊นŒ?
"๋ ˆ์ด์•„์›ƒ ์•ˆ์—์„œ ์„œ๋กœ ๋‹ค๋ฅธ ๋‘ ๊ฐœ์˜ API๋ฅผ ๋ถˆ๋ €๋Š”๋ฐ, ํ•˜๋‚˜๋งŒ ํ„ฐ์กŒ์–ด. ๋ ˆ์ด์•„์›ƒ๊ณผ ์ •์ƒ API ๋ทฐ๋Š” ์‚ด๋ฆด ์ˆ˜ ์žˆ๋Š”๊ฐ€?"

โŒ ์˜์ฒ ์ด์˜ ํ†ต์งœ ์—๋Ÿฌ ์ฒ˜๋ฆฌ (์ƒ์œ„ ๋ฃจํŠธ๋กœ ๋ชฝ๋•… ์—๋Ÿฌ ๋– ๋„˜๊ธฐ๊ธฐ)

์˜์ฒ ์ด๋Š” ๊ทธ๋ƒฅ ๊ท€์ฐฎ์•„์„œ ๋ฃจํŠธ ํด๋”(app/error.tsx) ํ•˜๋‚˜๋งŒ ๋งŒ๋“ค์–ด ๋’€์–ด.
๊ทธ๋ž˜์„œ ๋œ ์ค‘์š”ํ•œ ์‚ฌ์ด๋“œ๋ฐ” ์œ„์ ฏ ํ†ต์‹  ํ•˜๋‚˜ ๋ป—์—ˆ๋Š”๋ฐ, ๋ฉ”์ธ ๊ฒŒ์‹œ๊ธ€๊ณผ ํ—ค๋” ์ „์ฒด ํŠธ๋ฆฌ๊นŒ์ง€ ์ „๋ถ€ ์ƒˆํ•˜์–—๊ฒŒ ๋‚ ์•„๊ฐ€๋ฉด์„œ ์ € ์—๋Ÿฌ ๋ฐฉ๋ฒฝ ํ…์ŠคํŠธ๋งŒ ๋œ๋  ๋– ๋ฒ„๋ฆฌ๊ฒŒ ๋์ง€.

โœ… ์˜ํ˜ธ์˜ ๊ตญ์ง€์  ๋ฐฉ๋ฒฝ ์„ค๊ณ„ (ํŒŒํŽธ ์ชผ๊ฐœ๊ธฐ + Suspense ์กฐํ•ฉ)

export default function CommunityPage() {
  return (
    <article className="layout_grid">
      <MainHeader />
      
      {/* โš ๏ธ ๋ฉ”์ธ ๊ฒŒ์‹œํŒ: ๋งค์šฐ ์ค‘์š”!! ์—ฌ๊ธฐ์„œ ํ„ฐ์ง€๋ฉด ์ „์ฒด error.tsx ๊ฐ€ ์žก๋„๋ก ๋ƒ…๋‘”๋‹ค */}
      <MainPostList />
 
      {/* ๐Ÿ›ก๏ธ ๋œ ์ค‘์š”ํ•œ ์‚ฌ์ด๋“œ๋ฐ” ์œ„์ ฏ: 
          ์—ฌ๊ธฐ๋Š” ํ„ฐ์ ธ๋„ ์‚ฌ์ดํŠธ ์ด์šฉ์— ๋ฌด๊ด€ํ•˜๋ฏ€๋กœ ๋ณ„๋„์˜ ๋„๋ฉ”์ธ ํด๋”๋กœ ๋นผ์„œ ๊ฐœ๋ณ„ error.tsx ๊ด€ํ• ๊ถŒ์œผ๋กœ ๋‘๊ฑฐ๋‚˜, 
          ์ˆ˜๋™ <ErrorBoundary> ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ตฌ์—ญ์œผ๋กœ ๋ฌถ๊ณ  fallback UI๋ฅผ ์กฐ์šฉํžˆ ๋„์›Œ ๋ฉ”์ธ ํ™”๋ฉด์„ ์‚ด๋ฆฐ๋‹ค! */}
      <aside>
        <SidebarRankingWidget /> 
      </aside>
 
    </article>
  )
}

๐ŸŽฏ ํ•œ ๊ฑธ์Œ ๋”: ์ปดํฌ๋„ŒํŠธ ๋‹จ์œ„์˜ ์ •๋ฐ€ ํƒ€๊ฒฉ ์—๋Ÿฌ ์ฒ˜๋ฆฌ

์˜์ฒ ์ด๋Š” ๊ถ๊ธˆํ•ด์กŒ์–ด. "์˜ํ˜ธ ๋ฆฌ๋“œ ๋‹˜, ๊ทธ๋Ÿผ error.tsx ํŒŒ์ผ ์—†์ด๋Š” ํŠน์ • ์ปดํฌ๋„ŒํŠธ ํ•˜๋‚˜๋งŒ ๋”ฑ! ์žก์•„์„œ ๊ฒฉ๋ฆฌํ•  ์ˆœ ์—†๋‚˜์š”? ํด๋”๋ฅผ ๋งค๋ฒˆ ์ƒˆ๋กœ ๋งŒ๋“ค๊ธด ์ข€ ๋ฒˆ๊ฑฐ๋กœ์›Œ์„œ์š”."

์˜ํ˜ธ ๋ฆฌ๋“œ ๋‹˜์ด ์›ƒ์œผ๋ฉฐ ๋Œ€๋‹ตํ–ˆ์ง€. "๋‹น์—ฐํžˆ ์žˆ์ฃ ! error.tsx๋Š” ๋ผ์šฐํŠธ ๋‹จ์œ„์˜ ํฐ ๊ฒฉ๋ฒฝ์ด๋ผ๋ฉด, ์šฐ๋ฆฌ๊ฐ€ ์ง์ ‘ ErrorBoundary ์ปดํฌ๋„ŒํŠธ๋กœ ๊ฐ์‹ธ๋ฉด ๊ฐœ๋ณ„ ์ปดํฌ๋„ŒํŠธ ๋‹จ์œ„๋กœ ์ •๋ฐ€ ํƒ€๊ฒฉ ๋ฐฉ์–ด๊ฐ€ ๊ฐ€๋Šฅํ•ด์š”."

1) react-error-boundary ํ™œ์šฉ (๊ถŒ์žฅ)

๊ฐ€์žฅ ์šฐ์•„ํ•œ ๋ฐฉ๋ฒ•์€ ๊ฒ€์ฆ๋œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์“ฐ๋Š” ๊ฑฐ์•ผ. ํŠน์ • ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ„ฐ์ ธ๋„ ํŽ˜์ด์ง€ ์ „์ฒด๊ฐ€ ํ•˜์–—๊ฒŒ ๋ณ€ํ•˜๋Š” ๊ฑธ ๋ง‰์•„์ฃผ์ง€.

'use client'
 
import { ErrorBoundary } from 'react-error-boundary'
 
function ErrorFallback({ error, resetErrorBoundary }: any) {
  return (
    <div className="p-2 border border-red-200 bg-red-50 text-xs text-red-600">
      <p>์œ„์ ฏ ๋กœ๋“œ ์‹คํŒจ ๐Ÿ˜ญ</p>
      <button onClick={resetErrorBoundary} className="underline">๋‹ค์‹œ ์‹œ๋„</button>
    </div>
  )
}
 
export default function Sidebar() {
  return (
    <aside>
      <h3>์‹ค์‹œ๊ฐ„ ๋žญํ‚น</h3>
      {/* ๐Ÿ›ก๏ธ ์ด ์œ„์ ฏ ํ•˜๋‚˜๊ฐ€ ํ„ฐ์ ธ๋„ ์‚ฌ์ด๋“œ๋ฐ” ์ „์ฒด์™€ ๋ฉ”์ธ ํŽ˜์ด์ง€๋Š” ๋ฌด์‚ฌํ•ด! */}
      <ErrorBoundary 
        FallbackComponent={ErrorFallback}
        onReset={() => {
          // ๋‹ค์‹œ ์‹œ๋„ํ•  ๋•Œ ์ˆ˜ํ–‰ํ•  ๋กœ์ง
        }}
      >
        <SidebarRankingWidget />
      </ErrorBoundary>
    </aside>
  )
}

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด error.tsx๊ฐ€ ๋‹ด๋‹นํ•˜๋Š” 'ํŽ˜์ด์ง€ ์ „์ฒด' ํ˜น์€ 'ํด๋” ์ „์ฒด' ๋‹จ์œ„์˜ ๊ฑฐ์‹œ์  ๋ฐฉ์–ด์™€, ์ปดํฌ๋„ŒํŠธ ๋‹จ์œ„์˜ ๋ฏธ์‹œ์  ๋ฐฉ์–ด๋ฅผ ์กฐํ™”๋กญ๊ฒŒ ์„ž์–ด์„œ "์ ˆ๋Œ€ ์ฃฝ์ง€ ์•Š๋Š” ์•ฑ" ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด! ๐Ÿฃ
ํ•ต์‹ฌ ๋ฉ˜ํƒˆ ๋ชจ๋ธ: ๋ฐฉํญ๋ฌธ(error.tsx)์„ ์–ด๋”” ๊ณ„์ธต(ํด๋” ๋ ˆ๋ฒจ)์— ๋‘˜ ๊ฒƒ์ธ๊ฐ€?
์—๋Ÿฌ๊ฐ€ ๋‚œ ๊ณณ์— error.tsx๊ฐ€ ์—†๋‹ค๋ฉด? ์—๋Ÿฌ ๋…€์„๊ณผ ํŒŒ๊ดด์˜ ํญํ’์€ ์ž๊ธฐ๋ฅผ ๋ง‰์•„์ฃผ๋Š” ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ์ƒ์œ„ ํด๋”์˜ error.tsx๋ฅผ ๋งŒ๋‚  ๋•Œ๊นŒ์ง€ ๋์—†์ด ๋ถ€๋ชจ๋ฅผ ์ฐข์œผ๋ฉฐ ์—ญํ–‰(Bubble Up) ํ•œ๋‹ค.
๋”ฐ๋ผ์„œ, ์‚ด๋ ค์•ผ ํ•˜๋Š” ํ•ต์‹ฌ ๊ธฐ๋‘ฅ(Layout)์˜ ๋‚ด๋ถ€์— ๋ฐฉ๋ฒฝ์„ ์˜ค๋ฐ€์กฐ๋ฐ€ํ•˜๊ฒŒ ๊น”์•„์ฃผ๋Š” ๊ฒƒ์ด ํŒŒํŽธํ™” ์„ค๊ณ„์˜ ๊ฝƒ์ด๋‹ค!


๐Ÿšจ ์„œ๋ฒ„ ๋‹ค์šด ์ตœํ›„์˜ ๋ณด๋ฃจ: global-error.tsx ๐Ÿ”ด

์งˆ๋ฌธ ํ•˜๋‚˜ ํ•ด๋ณด์ž.
"๋งŒ์•ฝ์— ์ œ์ผ ๋ฐ”๊นฅ ๊ป๋ฐ๊ธฐ ๊ธฐ๋‘ฅ์ธ app/layout.tsx (html, body ํƒœ๊ทธ๊ฐ€ ์„ ์–ธ๋œ ๊ทธ๊ณณ!) ์ž์ฒด์—์„œ ์ฝ”๋“œ ์งœ๋‹ค๊ฐ€ ์—๋Ÿฌ๊ฐ€ ํ„ฐ์ง€๋ฉด ์–ด๋–กํ•ด? ์ œ์ผ ๋†’์€ ๊ณณ์ด๋‹ˆ๊นŒ ๊ฑ”๋ฅผ ๊ฐ์‹ธ์ฃผ๋Š” ๋ถ€๋ชจ(์ƒ์œ„) error.tsx๊ฐ€ ์„ธ์ƒ์— ์กด์žฌํ•˜์ง€ ์•Š์„ ํ…๋ฐ?!"

์ •๋‹ต์ด์•ผ. app/error.tsx ์กฐ์ฐจ๋„ ๋ฃจํŠธ layout.tsx์˜ ์—๋Ÿฌ๋ฅผ ๋ฐฉ์–ดํ•ด๋‚ด์ง€ ๋ชปํ•ด. (์˜ค์ง layout ๋‚ด๋ถ€์˜ ํŽ˜์ด์ง€๋“ค๋งŒ ๋ฐฉ์–ดํ•จ).
๊ฐ€์žฅ ๋ฌด๊ฑฐ์šด ์‹ , ๊ฐ€์žฅ ์ตœ์ƒ์œ„ layout.tsx์—์„œ ํ„ฐ์ง„ ์ ˆ์ฒด์ ˆ๋ช…์˜ ์—๋Ÿฌ๋ฅผ ๋‹ด์•„๋‚ด๋Š”, ๋ง ๊ทธ๋Œ€๋กœ ์ง„์งœ ์ˆจ๊ฒจ์ง„ ๋งˆ์ง€๋ง‰ ๋ธ”๋ž™๋ฐ•์Šค๊ฐ€ ์˜ˆ์•ฝ์–ด๋กœ ์กด์žฌํ•ด.

// app/global-error.tsx (์ตœ์ƒ๋‹จ ๋ฃจํŠธ ๊ตฌ์—ญ์—๋งŒ ์ƒ์„ฑ ๊ฐ€๋Šฅ)
'use client'
 
export default function GlobalError({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  return (
    // โš ๏ธ ์—ฌ๊ธด layout์ด ํ„ฐ์กŒ์„ ๋•Œ ๋Œ€์ฒด๋˜๋Š” ๊ณณ์ด๋‹ˆ๊นŒ 
    // ๋‚˜ ์Šค์Šค๋กœ๊ฐ€ ๋ฐ˜๋“œ์‹œ <html> <body> ๊ป๋ฐ๊ธฐ๋ฅผ ๋งŒ๋“ค์–ด๋‚ด์•ผ๋งŒ ํ•ด!!
    <html>
      <body>
        <h1>์‹œ์Šคํ…œ ์ฝ”์–ด ๋ถ•๊ดด (Global Error ๋ฐœ๋™)</h1>
        <p>์ „๋ฉด ์žฅ์•  ์กฐ์น˜ ์ค‘์ž…๋‹ˆ๋‹ค... {error.message}</p>
        <button onClick={() => reset()}>์žฌ๋ถ€ํŒ… ์‹œ๋„</button>
      </body>
    </html>
  )
}

๐Ÿ’ก ํŒ: global-error.tsx๋Š” ํ”„๋กœ๋•์…˜ ๋นŒ๋“œ์—์„œ๋งŒ ํ™œ์„ฑํ™”๋ผ. (๊ฐœ๋ฐœ์ž ํ™˜๊ฒฝ ํ„ฐ๋ฏธ๋„ ํŒ์—…์€ ๋ฌด์‹œํ•˜๊ณ  ํ™”๋ฉด ํ™•์ธ ๋ถˆ๊ฐ€). ์˜ค์ง ์ตœํ›„์˜ ๋‚  ๋ฐฐํฌ ํ™˜๊ฒฝ์—์„œ ์ตœ์ƒ์œ„ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ(layout.tsx)๊ฐ€ ๋””๋น„ ํ†ต์‹  ๋“ฑ์—์„œ ์ฃฝ์–ด๋‚˜๊ฐˆ ๋•Œ๋งŒ ํŠ€์–ด๋‚˜์˜ค๋Š” ๋‹ค์ดํ•˜๋“œ ์ „์‚ฌ์˜ ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•˜์ง€.


๐Ÿ’ฅ ์—๋Ÿฌ ํ•ด๊ฒฐ ์นดํƒˆ๋กœ๊ทธ

์—๋Ÿฌ ๋ฉ”์‹œ์ง€๊ฐ€ ๋œจ๋ฉด Ctrl+F๋กœ ๊ฒ€์ƒ‰ํ•ด๋ด.

โŒ Error Components must be Client Components...

์›์ธ: error.tsx ๋‚˜ global-error.tsx ํŒŒ์ผ ์ตœ์ƒ๋‹จ์—์„œ 'use client' ์„ ์–ธ์„ ๊นŒ๋จน์—ˆ์Œ.
ํ•ด๊ฒฐ์ฑ…: 1์ดˆ ๋งŒ์— ์ตœ์ƒ๋‹จ์— 'use client' ์จ์ฃผ๊ธฐ. (๋Ÿฐํƒ€์ž„ ์—๋Ÿฌ ๋ Œ๋”๋ง์— ํ•„์ˆ˜)

โŒ ๋ฃจํŠธ layout.tsx๊ฐ€ ํ„ฐ์กŒ๋Š”๋ฐ app/error.tsx๊ฐ€ ์ž‘๋™ ์•ˆ ํ•˜๊ณ  ํ•˜์–€ ์ฃฝ์Œ ํ™”๋ฉด ๋œน๋‹ˆ๋‹ค!

์›์ธ: app/error.tsx ๊ตฌ์กฐ์ƒ ์ž์‹ ์ด ์†ํ•œ layout.tsx ํ˜•์ œ ํŒŒ์ผ์˜ ์—๋Ÿฌ๋Š” ๋ง‰์ง€ ๋ชปํ•จ (์˜ค์—ผ ๋ฒ•์น™).
ํ•ด๊ฒฐ์ฑ…: ๋ฃจํŠธ app/ ๋ ˆ๋ฒจ ๊นŠ์ด์—์„œ๋Š” layout.tsx๋ฅผ ๊ฐ์‹ธ ๋ฐฉ์–ดํ•  ์ˆ˜ ์žˆ๋Š” global-error.tsx ํŒŒ์ผ์„ ๋ณ„๋„๋กœ ๋งŒ๋“ค์–ด์•ผ ์™„๋ฒฝํžˆ ์ฐจ๋‹จ๋จ.


๐Ÿ ์ด๋ฒˆ์— ๋ฐฐ์šด ๋‚ด์šฉ ์ด์ •๋ฆฌ

์—๋Ÿฌ ๋ฐœ์ƒ ์ปดํฌ๋„ŒํŠธ ํŒŒ์ผ์ž‘๋™ํ•˜๋Š” ๋ฐฉ์–ด ์‰ด๋“œ (์šฐ์„ ์ˆœ์œ„)์„ค๋ช…
app/dashboard/page.tsx1. app/dashboard/error.tsx๊ฐ™์€ ํด๋”(ํ˜•์ œ ๋ ˆ๋ฒจ)์˜ error.tsx๊ฐ€ ์ตœ์šฐ์„  ๊ฒฉ๋ฒฝ ๋ฐœ๋™
app/dashboard/layout.tsx1. app/error.tsx์ž๊ธฐ๊ฐ€ ํ„ฐ์กŒ์œผ๋ฏ€๋กœ, ๋‚ด ํ˜•์ œ error๋Š” ๋ฌด์šฉ์ง€๋ฌผ! ์ƒ์œ„ ๋ถ€๋ชจ ํด๋”์˜ error๊ฐ€ ์žก์•„์คŒ
app/layout.tsx (๋ฃจํŠธ)1. app/global-error.tsx์„ธ์ƒ์˜ ๋. ํ•˜๋Š˜์ด ๋ฌด๋„ˆ์กŒ์„ ๋•Œ ์ตœํ›„ ์‹ฌํŒ์ž. html ๊ป๋ฐ๊ธฐ ํ•„์ˆ˜
404 Not Found ๊ฐ•์ œ ํ˜ธ์ถœ1. app/not-found.tsx(์ด๊ฑด 9์žฅ์—์„œ ์‹ฌํ™” ํ•™์Šต) ์˜ˆ์ƒ๋œ ๋ฆฌ์†Œ์Šค ์ „์šฉ ์—†์Œ ์—๋Ÿฌ

๐Ÿ’ก ํ•œ ์ค„๋กœ ๊ธฐ์–ตํ•˜๊ธฐ
์—๋Ÿฌ๋Š” ๋ฌผ๊ณผ ๊ฐ™์•„์„œ ๋ฐฉ์ˆ˜๋ฌธ(error.tsx)์ด ์—†๋Š” ์œ—๋ฐฉ(๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ)์„ ํ–ฅํ•ด ๊ฟ€๋Ÿญ๊ฟ€๋Ÿญ ์ฐจ์˜ค๋ฅธ๋‹ค.
์ค‘์š”ํ•œ ๊ตญ์ง€ ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ์—๋Š” ์ด˜์ด˜ํ•˜๊ฒŒ ์‰ด๋“œ ํŒŒ์ผ์„ ํด๋” ๋‹จ์œ„๋กœ ์‹ฌ์–ด๋†”์•ผ, ์‚ฌ์ดํŠธ ์ „์ฒด๊ฐ€ ํŒŒ๊ดด๋˜๋Š” ๋Œ€์žฌ์•™ ์˜ค๋ฅ˜ ํ™”๋ฉด ์Šคํฌ๋ฆฐ(YOD: Yellow Screen of Death)์„ ๋ฉดํ•  ์ˆ˜ ์žˆ๋‹ค!


๐Ÿ“ ๋งˆ๋ฌด๋ฆฌ ํ€ด์ฆˆ

๋ฐฐ์› ์œผ๋ฉด ํ•œ ๋ฒˆ ๋น„ํ‹€์–ด์„œ ํ™•์ธํ•ด๋ด์•ผ ํ•ด.

Q1. ์˜์ฒ ์ด๊ฐ€ ์‡ผํ•‘๋ชฐ ๊ฒฐ์ œ ํŽ˜์ด์ง€ ํด๋”๋ฅผ ์„ธํŒ… ์ค‘์ด๋‹ค. app/purchase/ ํด๋” ๋‚ด๋ถ€์— layout.tsx, page.tsx, error.tsx ํŒŒ์ผ ์„ธ ๊ฐœ๊ฐ€ ์žˆ๋‹ค. ์–ด๋А ๋‚  page.tsx์—์„œ ์„œ๋ฒ„ ์•ก์…˜์„ ์ฒ˜๋ฆฌํ•˜๋‹ค throw new Error("๊ฒฐ์ œ ์Šน์ธ ๊ฑฐ๋ถ€") ๊ฐ€ ํ„ฐ์กŒ๋‹ค. ์ด๋•Œ, ํ™”๋ฉด ์ „์ฒด ๋ Œ๋”๋ง ์ธก๋ฉด์—์„œ ๋ณด์•˜์„ ๋•Œ purchase/layout.tsx ๋‹จ์—์„œ ๊ทธ๋ ค์ฃผ๋˜ GNB(๊ธ€๋กœ๋ฒŒ ์ƒ๋‹จ ๋„ค๋น„๊ฒŒ์ด์…˜)์™€ ์‚ฌ์ด๋“œ ์นดํŠธ ๋ฐ”๋Š” ์œ ์ € ํ™”๋ฉด์— ์‚ด์•„์žˆ์„๊นŒ? ๋‚ ์•„๊ฐ€์„œ ์•ˆ ๋ณด์ผ๊นŒ?

โœ… ์ •๋‹ต: ์™„๋ฒฝํ•˜๊ฒŒ ์‚ด์•„์žˆ๋‹ค (์œ ์ง€๋œ๋‹ค).

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

Q2. ๋ฐฉ์–ด๋ฒฝ์ธ error.tsx ํŒŒ์ผ ์•ˆ์—์„œ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ์—๋Ÿฌ๊ฐ€ ๋‚ฌ๋˜ ์›๋ž˜ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ•์ œ๋กœ ๋ป—๊ฒŒ ๋งŒ๋“  ์›์ธ์„ ๋’ค์—Ž๊ณ  ์ฒ˜์Œ๋ถ€ํ„ฐ ๋‹ค์‹œ fetch ํ•ด๋ณด๋ผ๊ณ  ์„œ๋ฒ„์— ์žฌ์š”์ฒญ(๊ฐ•์ œ ํšŒ๋ณต ๋ฆฌํ”„๋ ˆ์‹œ)์„ ๋ณด๋‚ด๋Š” ์—ญํ• ์„ ํ•˜๋Š” ํ•ต์‹ฌ Props ํŒŒ๋ผ๋ฏธํ„ฐ ํ•จ์ˆ˜ ์ด๋ฆ„์€ ๋ฌด์—‡์ธ๊ฐ€?

โœ… ์ •๋‹ต: reset() ํ•จ์ˆ˜์ด๋‹ค.

๐Ÿ’ก ์ƒ์„ธ ํ•ด์„ค: error.tsx ์ปดํฌ๋„ŒํŠธ๋Š” Next.js๋กœ๋ถ€ํ„ฐ ๋ฌด์กฐ๊ฑด ๋‘ ๊ฐœ์˜ ํ”„๋กญ์Šค ํŒจํ‚ค์ง€๋ฅผ ์ฅ๊ณ  ํƒœ์–ด๋‚œ๋‹ค. ํ•˜๋‚˜๋Š” ์—๋Ÿฌ ๋คํ”„ ๋ฉ์–ด๋ฆฌ์ธ error ์ƒ์ž, ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” ์ฃฝ์€ ์„น์…˜์„ ๋‹ค์‹œ ๋งˆ์šดํŠธ์‹œ์ผœ ๋ Œ๋”๋ง ์„œ๋ฒ„์™€ ๋‹ค์‹œ ํ†ต์‹ ์„ ๊ฐ•ํ–‰์ผ€ ํ•˜๋Š” reset ์•ก์…˜ ํ•จ์ˆ˜์ด๋‹ค. onClick={() => reset()} ์ฝ”๋“œ๋Š” SPA ์„ธ์ƒ์—์„œ ์ƒˆ๋กœ๊ณ ์นจ ์—†์ด ํ•ด๋‹น ๋ถ€๋ถ„ ์ปดํฌ๋„ŒํŠธ๋งŒ ํšŒ๋ณต ๋งˆ๋ฒ•์„ ๋ฐœ๋™์‹œํ‚ค๋Š” ๊ณ ๊ธ‰ ์น˜์œ ๊ธฐ(Heal)์ด๋‹ค.


๐Ÿฃ ์˜์ฒ ์ด์˜ ํ‡ด๊ทผ ์ผ๊ธฐ

์˜ค๋Š˜์€ ์ •๋ง ์‹ญ๋…„๊ฐ์ˆ˜ํ–ˆ์–ด. API ํ•˜๋‚˜ ํ„ฐ์กŒ๋‹ค๊ณ  ์‚ฌ์ดํŠธ ์ „์ฒด๊ฐ€ ๋ป—์–ด๋ฒ„๋ฆฌ๋Š” ๊ฑธ ๋ณด๋ฉด์„œ ํ”„๋ก ํŠธ์—”๋“œ ์„ธ๊ณ„์˜ ๋ฌด์„œ์›€์„ ๋А๊ผˆ๊ฑฐ๋“ . ํ•˜์ง€๋งŒ ์˜ํ˜ธ ๋ฆฌ๋“œ ๋‹˜์ด ๊ฐ€๋ฅด์ณ์ฃผ์‹  '๋ฐฉํ™” ์…”ํ„ฐ(error.tsx)' ์™€ ๋” ์„ธ๋ฐ€ํ•œ '๊ฐœ๋ณ„ ๊ฒฉ๋ฒฝ(ErrorBoundary)' ์˜ ์œ„๋ ฅ์„ ํ™•์ธํ•˜๊ณ  ๋‚˜๋‹ˆ ์ด์ œ๋Š” ์–ด๋–ค ์—๋Ÿฌ๊ฐ€ ํ„ฐ์ ธ๋„ ๋‹นํ™ฉํ•˜์ง€ ์•Š์„ ๊ฒƒ ๊ฐ™์•„!

๐Ÿ’ก ์˜ค๋Š˜์˜ ๊ตํ›ˆ: "์—๋Ÿฌ๋Š” ๋ฌผ๊ณผ ๊ฐ™์•„์„œ ๋ฐฉ์ˆ˜๋ฌธ(error.tsx) ์ด ์—†์œผ๋ฉด ์œ—๋ฐฉ์œผ๋กœ ์—ญ๋ฅ˜ํ•œ๋‹ค. ๋ผ์šฐํŠธ ๋‹จ์œ„์˜ ํฐ ์…”ํ„ฐ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, ์ปดํฌ๋„ŒํŠธ ๋‹จ์œ„์˜ ์ •๋ฐ€ํ•œ ๊ฒฉ๋ฒฝ(ErrorBoundary) ๋„ ์ ์žฌ์ ์†Œ์— ๋ฐฐ์น˜ํ•ด ์•ฑ์˜ ์ƒ์กด๋ ฅ์„ ๊ทน๋Œ€ํ™”ํ•˜์ž!"

๋‹จ์ˆœํžˆ try-catch ๋กœ ์—๋Ÿฌ๋ฅผ ์ˆจ๊ธฐ๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ, ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ ์ง€์ ์„ ๋ช…ํ™•ํ•˜๊ฒŒ ๊ฒฉ๋ฆฌํ•˜๊ณ  ์‚ฌ์šฉ์ž์—๊ฒŒ ๋‹ค์‹œ ์‹œ๋„ํ•  ๊ธฐํšŒ(reset) ๊นŒ์ง€ ์ฃผ๋Š” ์„ค๊ณ„๊ฐ€ ์–ผ๋งˆ๋‚˜ ์„ธ๋ จ๋œ ๋ฐฉ์‹์ธ์ง€ ๊นจ๋‹ฌ์•˜์–ด. ์˜ค๋Š˜ ๊ธด์žฅํ–ˆ๋”๋‹ˆ ์–ด๊นจ๊ฐ€ ๋ป๊ทผํ•˜๋„ค. ์šด๋™ ๊ฐ€์„œ ์ŠคํŠธ๋ ˆ์นญ ์ข€ ํ•˜๊ณ  ํ‘น ์‰ฌ์–ด์•ผ์ง€! ๋‚ด์ผ์€ ์—๋Ÿฌ ์—†๋Š” ๋ฌด๊ฒฐ์  ์ฝ”๋“œ๋ฅผ ์งœ๋Š” '๋””๋ฒ„๊น… ๋งˆ์Šคํ„ฐ' ๊ฐ€ ๋˜๊ณ  ๋ง ๊ฑฐ์•ผ. ๐Ÿฃ


๐Ÿ”— ๋” ์•Œ์•„๋ณด๊ธฐ