WEB/Next.js

[Next.js/13] use client와 use server 이해하기

heeney 2025. 1. 25. 22:34
728x90
반응형

들어가며

Next.js 13 이상에서는 App Router 도입과 함께 use client와 use server라는 개념이 등장했습니다.
이는 React Server Components(RSC)를 활용한 렌더링 방식의 최적화를 위한 것으로 클라이언트와 서버의 역할을 명확히 나눔으로써 성능과 개발자 경험을 향상하는 것에 초점을 맞추고 있습니다.

use client와 use server의 차이를 이해하고 각 기능이 필요한 경우와 실제 프로젝트에서 어떻게 활용할 수 있는지 정리하는 시간을 가져보겠습니다.

먼저 설명드리고 싶은 부분이 있는데, 바로 기본적으로 Next.js의 모든 컴포넌트는 서버 컴포넌트라는 것입니다.
이 부분을 인지한 후 들어가시는 것이 이해가 쉬울듯 하여 언급하였습니다.

use client

'use client' // 클라이언트 컴포넌트 선언

import { useState } from 'react'

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

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

 

위의 코드는 카운트 기능이 있는 컴포넌트 입니다. 다음과 같이 useState를 사용할 경우 'use client'를 선언해주어야 합니다.
그렇지 않으면 에러가 발생합니다. Next.js를 처음 접하면서 종종 만나게 될 수 있는 게 바로 클라이언트 컴포넌트에서 사용해야 하는 기능들을 서버 컴포넌트에서 실행했을 때입니다.

  • useState, useEffect 등 React 훅을 사용해야 할 때
  • 버튼 클릭, 입력 폼, 모달 등 사용자 이벤트를 처리할 때
  • Interactive UI (ex. 애니메이션, 상태 변경)를 구현할 때

 

API 호출의 경우 평소 하던 대로 useEffect로 호출할 수도 있겠지만, 가급적 서버 컴포넌트를 사용하는 것이 유리하므로 다음과 같이 실행하는 것이 좋습니다. 오히려 더 직관적이고 쉽기도 합니다.

export default async function Page() {
  const data = await fetch('https://api.vercel.app/blog')
  const posts = await data.json()
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}

use server

'use server'
import { db } from '@/lib/db'
 
export async function createUser(data) {
  const user = await db.user.create({ data })
  return user
}

서버에서 실행되어 데이터베이스 접근이 필요한 경우 안전하게 처리가 가능합니다.

  • 서버에서 실행해야 하는 비즈니스 로직이 있을 때
  • 데이터베이스에 직접 접근해야 할 때
  • API 요청을 서버에서 처리하고 결과를 반환할 때
  • 보안이 중요한 작업 (ex. 인증, 결제 처리 등)

그리고 클라이언트에서 서버 함수를 호출해야 하는 경우가 있는데요. 다음과 같이 사용할 수 있습니다.

import { db } from '@/lib/db'
 
export default function UserList() {
  async function fetchUsers() {
    'use server'
    const users = await db.user.findMany()
    return users
  }
 
  return <button onClick={() => fetchUsers()}>Fetch Users</button>
}

해당 코드는 inline 코드이지만, action.ts 파일을 따로 생성하여 코드를 분리할 수도 있습니다. 동일하게 사용하시면 됩니다.

최상단에 use server를 선언해 주면 fetchUsers는 클라이언트 컴포넌트에서 사용할 수 있는 서버 함수로 구분됩니다. 서버 컴포넌트에서의 모습도 궁금하실 텐데 앞서 설명드렸던 것처럼 서버 컴포넌트에 async await을 사용하여 데이터를 불러올 수 있습니다. 뒤에서도 설명드리겠지만 use server는 함수에서만 사용 가능하기 때문에 클라이언트에서는 직접 호출이 불가합니다.

이렇게 사용하면 클라이언트에서 직접 데이터베이스를 호출하지 않고 보안이 강화된 안전한 상태로 데이터를 요청할 수 있습니다.

use client와 use server의 차이점

  use client use server
실행환경 client (브라우저) server (Node.js)
사용 목적 상태 관리, 이벤트 핸들링, 인터렉션 UI, window 관련 데이터베이스 접근, API 요청, 비즈니스 로직
지원하는 훅 useState, useEffect, useRef 등
보안 민감한 데이터 저장 X 안전하게 데이터 처리 가능
기본적용 여부

알고 가면 좋은 부분 (유의사항)

  1. use client를 최소한의 범위로 적용하는 게 좋습니다 -> 불필요하게 남용하면 성능 저하 발생
  2. use server는 함수에서만 사용 가능하며 클라이언트에서 직접 호출 불가합니다.
  3. Next.js의 모든 컴포넌트는 기본적으로 서버 컴포넌트입니다.
  4. JS의 번들 크기가 감소할수록 성능은 최적화됩니다 -> 가급적 서버 컴포넌트를 기본으로 사용해야 하는 이유

참고

역시 공식문서: https://nextjs.org/

 

Next.js by Vercel - The React Framework

Next.js by Vercel is the full-stack React framework for the web.

nextjs.org

 

728x90
반응형