에러헨들링

하영·2024년 10월 10일
1

Next.js

목록 보기
11/19

에러헨들링

이전에도 loading쪽이랑 간단하게 정리를 했던 것 같은데 조금 디테일하게? 실습해 본 내용을 정리해보았다.

화면을 디자인했다거나 콘솔을 자주 확인한다거나 하기 보다는 코드 위주로 내용을 간단하게 정리해보면서 이런 메소드가 있고 이렇게 쓰는구나! 를 알아보자!

01. error.tsx 파일 생성하기

"use client";

import { useEffect } from "react";

// 오류라는건 서버,클라이언트 모든 환경에서 발생하기 때문에 다 대응할 수 있도록 만들기 위해 "use client" 명시

export default function Error({error}: {
  error: Error; //자바스크립트의 Error 타입을 props로 내려서 적용
}) {;

  useEffect(() => {
    console.error(error.message);
  }, [error]);

  return (
    <div>
      <h3>오류가 발생했습니다.</h3>
    </div>
  );
}

간단하게 search 폴더의 index page와 동일한 위치에 error.tsx로 파일 하나를 생성해주고 코드를 작성했다.

  • “use client” 를 맨 위에 명시

오류라는건 서버, 클라이언트 모든 환경에서 발생하는 것이기 때문에 어떤 환경이든 다 대응해서 보여줄 수 있도록 만들고자 “use client”를 적어준 것이다.

  • errorprop으로 전달받고 자바스크립트의 Error를 타입으로 명시해주었다. 그 다음 useEffect 훅을 사용해서 에러가 발생할 때마다 error의 메소드인 message를 콘솔에 출력되게 작성했다. 💡 error.tsx도 지금까지의 `layout`이나 `loading` 페이지처럼 `error` 아래에 있는 **모든 페이지에 영향**을 미치게 된다. 그러므로 이 `error` 페이지는 `search` 폴더 내의 모든 페이지에서 에러가 발생할 때 이 페이지의 화면이 보여질 것이다.

✅ 브라우저 화면 확인

(캡처 화면은 error.message 를 적용하지 않고 단순 error만 작성했을 때의 화면이다.)

이렇게 에러가 발생하면 어떤 부분에서 발생한 문제인지 확인할 수 있다.


02. reset 매개변수 추가하기

"use client";

import { useEffect } from "react";

export default function Error({
  error,
  reset,
}: {
  error: Error;
  reset: () => void; //어떠한 값도 받지 않는 void 타입
}) {

  useEffect(() => {
    console.error(error.message);
  }, [error]);

  return (
    <div>
      <h3>오류가 발생했습니다.</h3>
      <button onClick={() => reset()}>다시 시도</button>
    </div>
  );
}

error 는 또 다른 매개변수로 reset() 메소드를 받게 되는데 이 함수는 어떠한 값도 받지 않는 void 타입으로 정리해주었다.

  • reset() : 실행될 때마다 새로 렌더링 되는 메소드

reset 메소드가 적용된 버튼을 눌러도 화면이 다시 그려지지 않게 된다. 그 이유는 이 메소드는 브라우저 측에 저장된 화면을 다시 렌더링해주는 것이기 때문이다. ( → 데이터 패칭이 다시 수행되지 않는다는 뜻!)

따라서 서버컴포넌트를 재가동 시켜도 여전히 정상적으로 화면에 데이터가 불러와지지 않는다.

즉, 클라이언트 내부에서 발생한 오류만 해결해주는 메소드라서 추가 작업이 필요하다.


03. startTransition으로 해결하기

"use client";

import { useRouter } from "next/navigation";
import { startTransition, useEffect } from "react";

export default function Error({
  error,
  reset,
}: {
  error: Error; 
  reset: () => void; 
}) {

  const router = useRouter();

  useEffect(() => {
    console.error(error.message);
  }, [error]);

  return (
    <div>
      <h3>오류가 발생했습니다.</h3>
      <button
        onClick={() => {
          startTransition(() => {
            router.refresh();
            //-> RecoBooks나 AllBooks 의 서버 컴포넌트들을 다시 실행시켜서 데이터를 RSC Payload에 저장해서 불러와라! 하는것
            reset(); 
          });
        }}
      >
        다시 시도
      </button>
    </div>
  );
}
  • refresh() : 현재 페이지에 필요한 서버컴포넌트들을 다시 불러온다.
  • reset() : 에러 상태를 초기화하고 컴포넌트들을 다시 렌더링 한다.

useRouterrefesh는 서버컴포넌트들을 다시 실행 시켜서 그 데이터를 RSC Payload에 저장 후 다시 보여줘! 하는 것이다.

🧐 startTransition 를 사용하지 않고 아래처럼 코드를 작성한다면 어떻게 될까?

<button
  onClick={() => {
    router.refresh(); 
    reset(); 
  };
}
>
  다시 시도
</button>

refresh는 비동기적으로 실행되기 때문에 이렇게 작성할 경우 refresh의 작업이 다 끝나기도 전에 reset 메소드가 실행되어서 우리가 원하는 기능을 완성시킬 수 없다.

그렇다고 async / await 도 위 환경에서는 적용시킬 수 없다. 때문에 startTransition 이라는 리액트 기능을 사용해서 refreshreset이 동시에 작업이 실행되도록 구현하여 우리가 원하는 모습으로 만들어 준 것이다.

profile
왕쪼랩 탈출 목표자의 코딩 공부기록

0개의 댓글