Next.js - 에러 핸들링

RumbleBi·2024년 11월 20일
0

next.js 14v 정리

목록 보기
10/12
post-thumbnail

App router 에서의 에러 핸들링 방법

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 파일을 각각의 경로마다 설정해야 될 경우가 있다.

profile
기억보다는 기록하는 개발자

0개의 댓글