Next.js

Client와 Server 컴포넌트의 상태 관리

_HelloWorld_ 2024. 12. 18. 09:55

1. 클라이언트 컴포넌트의 상태 관리

클라이언트 컴포넌트란?

클라이언트 컴포넌트는 브라우저에서 렌더링되며, 사용자와의 상호작용 및 상태 관리를 담당합니다. 클라이언트 컴포넌트는 use client 지시문을 통해 명시적으로 선언

'use client';

import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);

  return (
    <button onClick={() => setCount(count + 1)}>
      Count: {count}
    </button>
  );
}

클라이언트 상태 관리 방법

클라이언트 컴포넌트는 React의 기본 상태 관리 도구와 외부 상태 관리 라이브러리를 활용할 수 있습니다.

1. React의 내장 상태 관리

  • useState와 useReducer로 간단한 상태를 관리.
  • 컴포넌트 수준의 상태에 적합.

2. Context API

  • 전역 상태 관리에 사용. 작은 규모의 애플리케이션에서 유용.
  • 하지만 상태 업데이트가 발생할 때마다 관련 컴포넌트가 다시 렌더링되는 단점이 있음.
'use client';

import React, { createContext, useContext, useState } from 'react';

const ThemeContext = createContext();

export function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');

  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

export function useTheme() {
  return useContext(ThemeContext);
}

3. 외부 상태 관리 라이브러리

  • Redux, Zustand, Recoil 등을 활용하여 더 복잡한 상태 관리 가능.
  • 클라이언트 측 데이터를 대규모로 관리하거나, 비동기 작업이 빈번한 경우 적합.
'use client';

import { create } from 'zustand';

const useStore = create((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
}));

export default function Counter() {
  const { count, increment } = useStore();

  return <button onClick={increment}>Count: {count}</button>;
}

2. 서버 컴포넌트의 상태 관리

서버 컴포넌트란?

서버 컴포넌트는 서버에서 렌더링된 후 브라우저로 전송됩니다. 서버 컴포넌트는 브라우저에 전송되기 전에 데이터를 가져오고 렌더링하기 때문에, 클라이언트로 전달되는 데이터의 양을 최소화할 수 있습니다.

서버 상태 관리 방법

서버 컴포넌트는 클라이언트와 달리 상태보다는 데이터를 관리하는 데 중점을 둡니다. 일반적으로 데이터베이스나 API에서 데이터를 가져와 컴포넌트에 전달하는 역할을 수행합니다.

 

1. fetch와 async/await를 활용한 데이터 페칭

서버 컴포넌트는 데이터를 가져오는 로직을 내장할 수 있습니다. 이는 클라이언트 컴포넌트보다 더 간단하고 효율적입니다.

export default async function UserList() {
  const res = await fetch('https://jsonplaceholder.typicode.com/users');
  const users = await res.json();

  return (
    <ul>
      {users.map((user) => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

2. cache와 revalidate로 데이터 관리

Next.js는 서버 컴포넌트에서의 데이터 캐싱을 기본 지원합니다.

  • fetch의 next 옵션으로 revalidate 설정을 통해 데이터의 갱신 주기를 관리할 수 있습니다.
export default async function Posts() {
  const res = await fetch('https://jsonplaceholder.typicode.com/posts', {
    next: { revalidate: 60 },
  });
  const posts = await res.json();

  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}

서버 컴포넌트 → 클라이언트 컴포넌트로 props 전달하기

구조 설명

  1. 서버 컴포넌트: 서버에서 데이터를 가져오거나 처리한 후, 클라이언트 컴포넌트에 props로 전달합니다.
  2. 클라이언트 컴포넌트: 전달받은 props를 활용해 상호작용하거나 UI를 구성합니다.

 

1. 서버 컴포넌트에서 데이터 준비

서버 컴포넌트는 데이터를 가져온 후 클라이언트 컴포넌트에 props로 전달합니다.

// app/page.tsx (서버 컴포넌트)
import ClientComponent from './components/ClientComponent';

export default async function Page() {
  // 서버 측 데이터 페칭
  const res = await fetch('https://jsonplaceholder.typicode.com/posts/1');
  const post = await res.json();

  return (
    <div>
      <h1>Post Details</h1>
      {/* 클라이언트 컴포넌트에 props 전달 */}
      <ClientComponent title={post.title} body={post.body} />
    </div>
  );
}

2. 클라이언트 컴포넌트에서 props 활용

클라이언트 컴포넌트는 서버 컴포넌트에서 받은 props를 사용합니다.

// app/components/ClientComponent.tsx
'use client'; // 클라이언트 컴포넌트로 선언

type ClientComponentProps = {
  title: string;
  body: string;
};

export default function ClientComponent({ title, body }: ClientComponentProps) {
  return (
    <div>
      <h2>{title}</h2>
      <p>{body}</p>
    </div>
  );
}

 

핵심 사항:

  • 서버 컴포넌트는 서버에서 데이터를 가져와 렌더링하고, 이를 props로 클라이언트 컴포넌트에 전달합니다.
  • 클라이언트 컴포넌트는 React의 useState, useEffect 등 클라이언트 측 훅을 사용하여 상태 관리와 다른 클라이언트 측 기능을 처리할 수 있습니다.
  • 서버에서 데이터는 초기 렌더링 시 클라이언트로 전달되지만, 클라이언트 측에서 상태나 이벤트 처리 등은 클라이언트 컴포넌트에서 담당합니다.