[Next.js] 서버 컴포넌트 자세히 알아보자 1.0 ver

김현수·2024년 5월 20일
0

Next

목록 보기
2/2


🖍️ 서버 컴포넌트 자세히 알아보자 1.0


  • 렌더링

    • Server Rendering

      • 사용자가 페이지를 로드
      • 즉시 초기 HTML 을 서버에서 생성하는 행위

    • HTML 파일 내에 내용이 있느냐 없느냐
      내용이 있다면 SSR 된 것

      • 서버 사전 렌더링
      • Markup
        (HTML 응답)
        (내용이 있고 초기화 되어있는 data)
      • JS (Hydration)

    • 해당 프로세스는 서버에 최소 2번 왕복
      • 데이터가 포함된 HTML 로드
      • JS 로드 (Hydration)

    • Client Rendering

      • Markup
        (비어있는 index.html)
      • JS + Query
        (데이터 가져오기)
      • 컨텐츠 렌더링
        (응답받은 후 DOM 업데이트)

    • 해당 프로세스는 서버에 최소 3번 왕복
      • 초기 HTML 로드
      • JS 로드
      • 데이터 가져오기

Markup 이 완료되면 사용자는 컨텐츠를 볼 수 있음


  • Hydration

    • 서버에서 렌더링된 정적 HTML 에 JS 를 첨부하는 프로세스

    • 컴포넌트를 렌더링하고 이벤트 핸들러를 연결하는 프로세스


    • 초기 HTML 이미 사용자에게 표시
    • JS 는 이벤트 리스너와 동적 동작을 로드하여
      기존 DOM 요소에 연결

    • SSR 을 하이드레이션과 함께 사용하면 JavaScript가 로드된 후 완전한 대화형 페이지로 초기 로드 시간이 단축

    • Client Side 에서 직렬화된 상태를 받아
      react-query의 상태로 변환
    • 서버에서 미리 가져온 데이터를
      Client 쿼리 캐시에 적용
    • 네트워크 요청 없이 데이터 사용 가능

  • Dehydration & Rehydration

    • 상태 관리, 특히 React Query 또는 Redux 와 같은 도구에서 일반적으로 사용

    • 서버와 클라이언트 간에 상태를 효율적으로 전송하고 복원하는 데 사용


    • Dehydration

      • 서버에서 데이터를 가져온 후, 이 데이터를 직렬화하여 클라이언트로 전송
      • 일반적으로 상태를 다른 환경으로 전송할 목적
        (예: 서버에서 클라이언트로)
      • 클라이언트 측 애플리케이션에서 직렬화된 형식으로 상태를 추출하는 프로세스
      • SSR 이 HTML 과 함께 미리 가져온 데이터를 보내는 데 유용

    • Rehydration

      • 페이지가 클라이언트에 로드될 때 직렬화된 상태(디하이드레이션된 상태)를 가져와 애플리케이션 상태로 다시 초기화하는 프로세스



📰 CODE 예시

  • Next.js 13 이후 (APP Routing)
  • useQuery 사용 전제
  • Typescript 사용 전제

  • 1단계, Server Component 설정

    • 미리 데이터를 가져와 Client Component 에 전달하는 Server Component 를 구현
    • app/posts/page.tsx
import {fetchPosts} from "@/app/services/PostService";
import PostList from "@/app/components/PostList";
import { dehydrate, Hydrate, QueryClient } from "@tanstack/react-query";
import { ReactNode } from "react";

export const revalidate = 0;

async function getDehydratedState() {
   const queryClient = new QueryClient();
   await queryClient.prefetchQuery('post', fetchPosts);
   return dehydrate(queryClient);
}

export default async function PostsPage() {
   const dehydrateState = await getDehydratedState();
  
   return (
      <Hydrate state={dehydrateState}>
         <PostList />
      </Hydrate>
   );
}

  • 2단계, useQuery 를 사용한 Client Component

    • useQuery 를 사용하여 데이터 패칭 후 표시하는 Client Component 구현
    • Server Component 에서 미리 가져온 데이터를 Hydration
'use client';

import React from 'react';
import { useQuery } from '@tanstack/react-query';
import { fetchPosts } from '@/app/services/PostService';
import styled from 'styled-components';

interface Post {
   id: number;
   title: string;
   body: string;
}

const PostList: React.FC = () => {
   const {data: posts, isLoading, error} = useQuery<Post[]>('posts', fetchPosts);
  
   if (isLoading) return <div>Loading...</div>;
   if (error) return <div>Rrror loading posts</div>;
  
   return (
      <List>
       {posts?.map(post => (
          <ListItem key={post.id}>
            <h2>{post.title}</h2>
            <p>{post.body}</p>
          </ListItem>
       ))}
      </List>
   );
};

export default PostList;

const List = styled.ul`
  list-style-type: none;
  padding: 0;
`;

const ListItem = styled.li`
  padding: 10px;
  border-bottom: 1px solid #ccc;

  h2 {
    margin: 0;
  }
`;



📢 SSR 의 Hydration ERROR

  • 서버에서 렌더링된 HTML 과 클라이언트에서 렌더링된 HTML 불일치
  • 서버와 클라이언트 간의 렌더링 논리 차이
  • 동적 데이터 가져오기와 관련된 타이밍 문제 등

  • 디버깅 (원인)

    • 서버와 클라이언트의 타이밍 문제 (HTML 불일치, 원인)
    • 서버와 클라이언트에서 렌더링에 사용되는 상태 불일치
    • 서버와 클라이언트에서 조건부로 다르게 렌더링되는 컴포넌트
profile
일단 한다

0개의 댓글