241213

우지끈·2024년 12월 13일

React Server Component 주의 사항


1. 당연한말
2. 사전렌더링 과정에서 한 번 실행되고, hydration 때 또 한 번 총 두 번 실행
3. 사전 렌더링 과정에서는 문제가 없겠지만 hydration 때 서버 컴포넌트 코드는 실행되지 않기에 런타임 에러 발생할 것
4. 사전 렌더링 때는 일단 서버 컴포넌트 먼저 RSC Payload로 변환되고 그 다음에 클라이언트 컴포넌트를 실행시켜 html을 생성하는데 이때 RSC Payload는 직렬화된 형태 \to 함수는 직렬화 될 수 없어 전달 불가능

  • hydration 때는 JS bundle만 전달하는게 맞음
  • 근데 페이지 이동(or Prefetcing)시에는 JS bundle이랑 RSC Payload도 같이 전달됨
    프리패칭시:
    • static 페이지: js bundle + RSC Payload
    • dynamic 페이지: RSC Payload만(js bundle은 실제 페이지 이동시에 받아옴)

Request Memoization vs Data Cache

Request Memoization

  • 한 페이지를 렌더링 하는 과정에서 중복된 api 요청들을 한 번만 보내서 메모이제이션 해두고 그 뒤로는 요청 x -> 메모이제이션 된 데이터 사용
  • 페이지 렌더링 끝나면 모든 캐시 소멸

Data Cache

  • 거의 영구적 -> 서버 죽을 때까지 남아있음

둘의 관계

  • 렌더링 중에는 Request Memoization이 우선적으로 작동 -> 이때 Data Cache는 아직 관여 x
  • 렌더링 후에 첫 요청이 발생하면 그때 Data Cache에 캐싱(옵션에 따라)

Static Page vs Dynamic Page

서버 컴포넌트만 해당(클라이언트 컴포넌트는 페이지 유형에 영향 x)

Static Page(Full Route Cache 적용됨)

  • Dynamic Page가 아니면 모두 Static Page (Default)

Dynamic Page
특정 페이지가 접속 요청을 받을 때마다 매번 변화가 생기거나, 데이터가 달라질 경우

  • 캐시되지 않는 Data Fetching을 사용할 경우
  • 동적 함수(쿠키, 헤더, 쿼리스트링)을 사용하는 컴포넌트가 있을 때
  • 풀라우트 캐시만 적용 못하는거지 나머지 캐싱은 다 가능


Full Route Cache도 내부 컴포넌트 중 revalidate 옵션이 걸린게 하나라도 있으면 같이 revalidate 됨

client router cache


공동된 레이아웃 같은 거 캐시에 보관 -> 새로고침하면 사라짐

Component streaming

    <Suspense key={searchParams.q || ""} fallback={<div>Loading...</div>}>
      <SearchResult q={searchParams.q || ""} />
    </Suspense>

원래 suspense는 처음 한 번 렌더링 이후에는 다시 로딩상태로 돌아가지 x -> key값을 주어 key값이 변경될 때마다 suspense를 새로 생성하게 하면 로딩상태 유지 가능(리액트는 key값이 달라지면 새로운 컴포넌트라고 인식하기때문)

Error handling

"use client";

import { useRouter } from "next/navigation";
import { 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(); 
            reset();
          });
        }}
        다시 시도
      </button>
    </div>
  );
}
  • use client 써주는 이유 -> 클라이언트 컴포넌트는 서버, 브라우저 환경에서 총 두 번 실행되므로 어디서 에러가 나든 핸들링 가능!
  • reset(): 클라이언트 측에서 서버에서 받았던 데이터를 기반으로 다시 렌더링 -> 클라이언트 컴포넌트 내부에서 발생한 에러만 복구 가능
  • refresh(): 넥스트야 서버 컴포넌트를 다시 실행시켜 RSC Payload 다시 보내줘 -> 현재 페이지에 필요한 서버 컴포넌트만 다시 불러옴
  • startTransition: 콜백 안에 들어있는 모든 UI 작업들을 일괄적으로 처리해주는 메서드(React18) -> refresh()는 비동기적으로 동작하는 메서드이기에 이걸로 감싸주지 않으면 refresh가 되기 전에 reset이 시작되어 페이지 복구가 안될 것

-> 그럼 refresh만 하면 되는 거 아닌가? : ㄴㄴ reset()은 에러 상태를 초기화 시켜주는 역할도 하기에 필요함


layout, error, loading 페이지들은 해당 파일 경로 + 하위 경로까지 동일하게 적용

0개의 댓글