개발자 되는 법.../TIL...
2024.10.07
개발_자
2024. 10. 8. 01:24
클라이언트 컴포넌트에서 서버 컴포넌트에서 하듯
if (!championsData || !rotationData) {
throw new Error(
"무료 챔피언 데이터를 가져오는 데 실패했습니다"
);
}
코드를 작성하니 에러 UI는 안 보이고 콘솔에 찍힌 에러 메시지만 보였다.
에러 UI가 보이지 않는 이유는..
1. 에러 바운더리 설정
Next.js에서 에러 바운더리는 기본적으로 서버 컴포넌트에서만 작동한다. ErrorBoundary를 클라이언트 컴포넌트에서 사용하려고 하면, 에러가 발생한 컴포넌트에 대해 즉시 렌더링되지 않거나, 특정 오류 처리 로직이 적용되지 않을 수 있다.
2. 클라이언트 컴포넌트에서의 에러
RotationPage는 클라이언트 컴포넌트로 설정되어 있지만, 만약 getChampionRotation 또는 fetchChampions함수에서 발생하는 에러가 이 컴포넌트의 상위 트리에서 처리되지 않는다면, 해당 에러는 에러 UI를 통해 표시 되지 않는다. 이 경우, 에러가 발생한 순간에 해당하는 트리에서 에러 UI로의 전달이 제대로 되지 않을 수 있다.
3. 데이터 fetching의 처리 방식
fetchChampions와 getChampionRotation이 실패하면, 에러를 로그로 출력하기만 하고 실제로는 UI에서 에러를 보여주지 않는다. UI에서 에러를 보여주기 위해서는 에러 상태를 관리해야 한다.
... 아직 어렵다 조금 더 이해하고 써야 할 것 같다.
"use client";
import { Champion } from "@/types/Champion";
import { ChampionRotation } from "@/types/ChampionRotation";
import { getChampionRotation } from "@/utils/riotApi";
import React, { useEffect, useState } from "react";
import { ChampionCard } from "../components/ChampionCard";
import { fetchChampions } from "@/utils/serverApi";
import ErrorBoundary from "../components/ErrorBoundary";
const RotationPage = () => {
const [rotation, setRotation] = useState<ChampionRotation | null>(null);
const [champions, setChampions] = useState<Champion[] | null>(null);
const [error, setError] = useState<Error | null>(null); // 에러 상태 관리
const fetchRotationData = async () => {
try {
const rotationData = await getChampionRotation();
const championsData = await fetchChampions();
if (!championsData || !rotationData) {
throw new Error(
"무료 챔피언 데이터를 가져오는 데 실패했습니다"
);
}
setRotation(rotationData);
setChampions(championsData);
} catch (err) {
setError(err as Error); // 에러 상태 업데이트
}
};
useEffect(() => {
fetchRotationData();
}, []);
let freeChampions: Champion[] = [];
if (champions !== null) {
freeChampions = champions.filter((champion) =>
rotation?.freeChampionIds.includes(Number(champion.key))
);
}
// 리셋 함수: 에러 상태 초기화 후 데이터를 다시 불러옴
const reset = () => {
setError(null);
setRotation(null);
setChampions(null);
fetchRotationData();
};
return (
<ErrorBoundary error={error} reset={reset}>
<div className="flex flex-col items-center w-full min-w-[100%] p-[70px] gap-[50px]">
<h1 className="text-[25px] text-[#C8AA6E]">
이번 주 무료 챔피언
</h1>
<ChampionCard data={freeChampions} />
</div>
</ErrorBoundary>
);
};
export default RotationPage;
import React, { ReactNode } from "react";
type ErrorBoundaryProps = {
children: ReactNode;
error: Error | null; // 에러 상태를 받을 수 있도록 타입 정의
reset: () => void; // 에러를 리셋하는 함수
};
const ErrorBoundary = ({ children, error, reset }: ErrorBoundaryProps) => {
if (error) {
// 에러 발생 시 표시할 UI
return (
<div className="flex flex-col justify-center items-center mt-[130px]">
<h2 className="text-[30px] mb-[5px]">오류 발생!</h2>
<p>{error.message}</p>
<button
onClick={reset}
className="border-[3px] border-[#59C1DE] text-[#59C1DE] py-[8px] px-[20px] rounded-[10px] mt-[80px] transition:all duration-300 ease-in-out hover:bg-[#59C1DE] hover:text-[#010101]"
>
다시 시도
</button>
</div>
);
}
return <>{children}</>; // 에러가 없을 경우 자식 컴포넌트를 그대로 렌더링
};
export default ErrorBoundary;