작성
·
41
0
next 공식문서를 살펴보면 단순 서버 fetch (서버액션x) 관련 에러 핸들링 방법은 딱히 안나와 있는 것 같아 질문드립니다.
만약 SectionA, SectionB, SectionC 서버 컴포넌트 내에서 각각 서버 fetch가 일어난다 가정했을 때 SectionB에서만 요청이 실패했다면 SectionB 영역만 fallback ui를 띄우고 나머지 SectionA, SectionC는 정상적으로 데이터를 렌더링하도록 구현하는 방법이 없을까요?
error-boundary 라이브러리는 클라이언트 환경에서만 사용가능해 서버 컴포넌트에선 사용할 수 없고 next 내부적으로 설계되어있는 에러 바운더리(error.js 등)는 전역에러를 캐치하는 걸로 알고있습니다. 때문에 페이지 내 특정 영역만 fallback ui를 띄우는 용도는 아닌 것 같더라구요.
혹시 다른 방법이 있나 궁금합니다 감사합니다!!
답변 2
0
답변이 늦었습니다 🙇♂
우선 포인트 짚은 좋은 질문 주셔서 감사합니다. 답변 먼저 드릴게요 🤗
가능합니다. “섹션 단위로만 실패 UI”를 띄우는 방법은 두 가지가 있어요.
섹션 내부에서 에러를 ‘잡고’ 소프트-페일(fallback을 직접 렌더)
App Router의 세그먼트 단위 에러 바운더리를 활용(= error.tsx
), 섹션을 Parallel Routes로 분리
말씀하신 방법 중에 error.tsx는 세그먼트 단위로 에러를 잡기에 추가적인 수정(라우팅 구조 관련)이 필요합니다. 우선 간단한 1번부터 자세히 설명드릴게요.
Server Component 안에서 fetch
를 직접 try/catch
로 감싸고, 실패 시 그 섹션만 대체 UI를 조건부 렌더링 하는 방법입니다. fetch
는 네트워크 오류에서만 throw하고, HTTP 에러는 res.ok
로 판별할 수 있어요.
// SectionB.tsx (Server Component)
export default async function SectionB() {
try {
const res = await fetch(process.env.API_URL + '/b', { cache: 'no-store' });
if (!res.ok) {
// 섹션 전용 fallback
return <SectionBFallback status={res.status} />;
}
const data = await res.json();
return <SectionBView data={data} />;
} catch (err) {
// 네트워크/파싱 등 예외
return <SectionBFallback />;
}
}
이 방식은 A, C는 정상 렌더, B만 fallback이 됩니다. 서버 액션이 아니어도 문제없어요. (Next 공식 가이드도 렌더 이후 비동기/이벤트성 에러는 바운더리가 못 잡으니 직접 처리하라고 안내합니다. (Next.js))
장점: 구조 변경 없음.
단점: “던지는(throw) 에러”를 경계로 분리해서 다루는 건 아님(즉, 바운더리가 아니라 “조건부 렌더”).
error.tsx
Next.js는 세그먼트 단위로 에러 바운더리를 둡니다. 같은 URL 안에서도 Parallel Routes(@slot) 를 쓰면 각 슬롯에 개별 error.tsx
를 둘 수 있어요. B만 실패해도 B 슬롯만 에러 UI가 나옵니다. (Next.js)
예시 구조:
app/dashboard/
page.tsx // 전체 레이아웃에서 슬롯을 배치
@a/page.tsx // SectionA
@a/default.tsx
@b/page.tsx // SectionB
@b/error.tsx // B 전용 에러 UI
@b/default.tsx
@c/page.tsx // SectionC
@c/default.tsx
page.tsx
(부모)에서 슬롯을 배치:
export default function Dashboard({
a, b, c,
}: { a: React.ReactNode; b: React.ReactNode; c: React.ReactNode }) {
return (
<main className="grid gap-6">
{a}
{b} {/* B만 실패하면 여기만 error.tsx로 대체 */}
{c}
</main>
);
}
@b/error.tsx
는 반드시 Client Component여야 하고, reset()
으로 재시도 버튼을 만들 수 있습니다. (Next.js)
'use client';
export default function Error({
error,
reset,
}: { error: Error & { digest?: string }, reset: () => void }) {
return (
<div>
<h2>섹션 B에서 오류가 발생했습니다.</h2>
<button onClick={() => reset()}>다시 시도</button>
</div>
);
}
장점: 진짜 “경계 격리”. 스트리밍 중에도 해당 슬롯만 대체 UI로 전환.
단점: 라우팅(폴더) 구조를 바꿔야 함.
참고: 말씀해주신 것처럼, 일반적인 커스텀
<ErrorBoundary>
컴포넌트(react-error-boundary 등)를 JSX로 감싸는 것만으로는 서버 컴포넌트에서 던진 에러를 못 잡는 제약이 있습니다. App Router에선 세그먼트error.tsx
를 두어야 안정적으로 잡혀요. (GitHub)
빠른 적용/섹션별 단순 실패 처리 → 1) Soft fail (try/catch + 조건부 렌더)
스트리밍/격리/리트라이까지 갖춘 정석 분리 → 2) Parallel Routes + error.tsx
공식 문서 요약:
에러 바운더리는 세그먼트 레벨에서 중첩 배치 가능(그 아래만 잡음), error.tsx
는 클라이언트 컴포넌트여야 함. (Next.js)
Parallel Routes는 각 슬롯별 독립 로딩/에러 상태를 제공. (Next.js)
지금 쓰고 계신 페이지 구조에 맞춰 해결책을 선택하실 수 있을거여요. 리팩터링 없이 Soft fail 패턴으로 우선 적용하거나, Parallel Routes로 분리하는 파일 구조를 적용하는 방식으로요.
0
안녕하세요, 인프런 AI 인턴입니다. 변재정님.
Next.js에서 서버 컴포넌트의 각 섹션에 대해 개별적인 에러 핸들링 및 폴백 UI를 구현하려는 경우, 기본적인 서버 컴포넌트의 에러는 전역으로 처리되기 때문에 다소 제한적일 수 있습니다. 그러나 이를 구현할 몇 가지 방법이 있습니다.
export default async function PageComponent() {
const [resultA, resultB, resultC] = await Promise.allSettled([
fetchSectionA(),
fetchSectionB(),
fetchSectionC()
]);
return (
<div>
{resultA.status === "fulfilled" ? <SectionA data={resultA.value} /> : <FallbackA />}
{resultB.status === "fulfilled" ? <SectionB data={resultB.value} /> : <FallbackB />}
{resultC.status === "fulfilled" ? <SectionC data={resultC.value} /> : <FallbackC />}
</div>
);
}
async function fetchWithFallback(fetchFunction, fallbackData = null) {
try {
const response = await fetchFunction();
return response;
} catch (error) {
console.error('Fetch failed:', error);
return fallbackData; // 사용할 기본 데이터
}
}
Next.js의 current 커스텀 에러 핸들링 기능으로는 서버 컴포넌트 내에서 부분적인 에러 바운더리 설정이 제한적이므로, 위와 같이 Promises와 개별 fetch 처리 함수를 사용하여 각 섹션별 에러를 개별적으로 핸들링하셔야 합니다.
또한, 이미 알고 계신 것처럼 클라이언트 환경에서의 ErrorBoundary
와 유사한 기능은 서버 컴포넌트에서 직접적으로 지원되지 않으며, 레이아웃 경로 내의 error.js
파일은 페이지 수준의 에러를 처리합니다.
관련된 논의를 참고하기 위해 Parallel Route를 사용한 모달에 대해 질문을 들어가 확인해보세요. 이 게시물에서도 에러와 관련된 Next.js의 라우트와 관련된 설명이 있습니다.
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.