next.js에서 지원하는 에러 핸들링에 대한 error.tsx기능은 매번 try-catch
로 에러 핸들링을 작성해야되는 불편함을 개선하여 나온 것이다.
페이지 폴더에 error.tsx
파일을 만들고,
"use client";
export default function Error() {
return (
<div>
<h3>오류가 발생했습니다.</h3>
</div>
);
}
이렇게 작성해주면 만약 에러가 났을 경우 page 컴포넌트대신 error 컴포넌트를 보여주게 된다.
여기서 왜 "use client"
라는 것을 설정해야하냐면,
기본적으로 오류라는 것은 서버든지 클라이언트던지 어떤 환경에서든 발생할 수 있기 때문이다. 서버든 클라든 어디서 문제가 일어나도 에러 컴포넌트가 보일 수 있도록 하는 것이다.
next.js는 자동으로 Error 컴포넌트에 error에 대한 정보를 자동으로 props로 넘겨준다.
"use client";
import { useEffect } from "react";
export default function Error({ error }: { error: Error }) {
useEffect(() => {
console.error(error);
}, [error]);
return (
<div>
<h3>오류가 발생했습니다.</h3>
</div>
);
}
또한 추가적으로 reset
이라는 props를 제공한다. 이는 다시 컴포넌트를 다시 렌더링하도록 시도하게 하는 함수이다.
"use client";
import { useEffect } from "react";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
useEffect(() => {
console.error(error);
}, [error]);
return (
<div>
<h3>오류가 발생했습니다.</h3>
<button onClick={() => reset()}></button>
</div>
);
}
여기서 리렌더링을 한다는 것은 클라이언트 단에서만 다시 리렌더링을 실시하는 것이다. 이미 서버에서 받은 데이터를 기반으로 수행하는 것이다. 즉 데이터 패칭같은 행위를 하지 않는다.
가장 쉬운 해결방법은 새로고침을 window.location.reload()
를 사용해서 다시 서버에서 데이터를 가져오게 하는것이다.
그런데 이러한 경우에는 가지고 있던 데이터들이 날아가기도 하고, 문제없는 컴포넌트들도 다시 렌더링해야 하기 때문에 다소 아쉬운 방법이다.
개선된 핸들링을 한다면,
"use client";
import { useRouter } from "next/navigation";
import { startTransition, useEffect } from "react";
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
useEffect(() => {
console.error(error);
}, [error]);
const router = useRouter();
return (
<div>
<h3>오류가 발생했습니다.</h3>
<button
onClick={() => {
startTransition(() => {
router.refresh();
reset();
});
}}
></button>
</div>
);
}
router.refresh()
를 사용해서 재요청이 필요한 부분만 다시 렌데이터를 서버에서 요청하여 해결할 수 있다.
router.refresh() 란? 현재 페이지에 필요한 서버컴포넌트들을 다시 불러오는 것. (비동기적으로 동작함)
reset()
그러면 왜 추가하는가? 에 대한 이유는, 에러 상태를 초기화하고 컴포넌트들을 다시 렌더링하는 것이다. client 컴포넌트의 에러상태는 refresh로는 초기화되지 않기 때문에 추가로 호출하는 것이다.
여기서 startTransition()
을 추가한 이유는 refresh 메서드 자체가 비동기적으로 사용
되기 때문이다. 익명함수에 async 를 붙이고 refresh에 await 을 붙여도 비동기적으로 동작하지 않기 때문에.
startTransition 메서드는 콜백함수안에 있는 UI를 변경시켜주는 작업을 일괄적으로 처리해주는 메서드이다.
error.tsx 파일은 하위 경로의 파일에도 동일하게 적용되는데,
하위 경로의 페이지 error.tsx 가 있다면 루트쪽 error.tsx가 아닌 같은 경로에 있는 error.tsx 파일이 보여지게된다.
또 주의해야 할 점은 error.tsx 파일을 app 폴더경로에 넣게 되면 app폴더의 layout.tsx 파일만 렌더링이 되어 만약 인덱스페이지에 검색창같은 컴포넌트가 있을 경우 보이지 않게 된다.
이래서 각각 error.tsx 파일을 각각의 경로마다 설정해야 될 경우가 있다.