icon안동민 개발노트

클라이언트 컴포넌트 사용법


 Next.js의 App Router에서 클라이언트 컴포넌트는 브라우저에서 실행되며 사용자 상호작용을 처리하는 데 중요한 역할을 합니다. 이 절에서는 클라이언트 컴포넌트의 사용법, 특징, 그리고 서버 컴포넌트와의 조합 전략에 대해 알아보겠습니다.

'use client' 지시어

 클라이언트 컴포넌트를 선언하려면 파일 최상단에 '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)}>Increment</button>
    </div>
  )
}

 이 지시어는 해당 파일과 그 하위에서 임포트하는 모든 모듈이 클라이언트 번들에 포함되도록 합니다.

클라이언트 컴포넌트의 특징

  1. 브라우저 API 접근 : window, document 등의 브라우저 API를 사용할 수 있습니다.
  2. 상태 관리 : React의 useState, useReducer 등을 사용할 수 있습니다.
  3. 이벤트 리스너 : onClick, onChange 등의 이벤트를 처리할 수 있습니다.
  4. 생명주기 메서드 : useEffect, useLayoutEffect 등을 사용할 수 있습니다.
  5. 클라이언트 사이드 라우팅 : Next.js의 Link 컴포넌트나 router.push를 사용할 수 있습니다.

상호작용 처리 방법

 클라이언트 컴포넌트에서는 일반적인 React 방식으로 상호작용을 처리할 수 있습니다.

'use client'
 
import { useState } from 'react'
 
export default function TextInput() {
  const [text, setText] = useState('')
 
  return (
    <div>
      <input
        type="text"
        value={text}
        onChange={(e) => setText(e.target.value)}
      />
      <p>You typed: {text}</p>
    </div>
  )
}

서버 컴포넌트와의 조합 전략

  1. 서버 컴포넌트 내 클라이언트 컴포넌트 사용 : 서버 컴포넌트 내에서 클라이언트 컴포넌트를 import하여 사용할 수 있습니다.
// ServerComponent.js
import ClientComponent from './ClientComponent'
 
export default function ServerComponent() {
  return (
    <div>
      <h1>Server Component</h1>
      <ClientComponent />
    </div>
  )
}
 
// ClientComponent.js
'use client'
 
export default function ClientComponent() {
  return <button onClick={() => alert('Clicked!')}>Click me</button>
}
  1. Props를 통한 데이터 전달 : 서버 컴포넌트에서 가져온 데이터를 클라이언트 컴포넌트에 props로 전달할 수 있습니다.
// page.js (Server Component)
import ClientList from './ClientList'
 
async function getData() {
  const res = await fetch('https://api.example.com/data')
  return res.json()
}
 
export default async function Page() {
  const data = await getData()
  return <ClientList items={data} />
}
 
// ClientList.js (Client Component)
'use client'
 
export default function ClientList({ items }) {
  return (
    <ul>
      {items.map(item => <li key={item.id}>{item.name}</li>)}
    </ul>
  )
}

클라이언트 컴포넌트의 적절한 사용 사례

  1. 사용자 입력 처리가 필요한 폼
  2. 클릭, 스크롤 등의 상호작용이 필요한 UI 요소
  3. 브라우저 API를 사용해야 하는 기능 (예 : geolocation)
  4. 클라이언트 사이드 상태 관리가 필요한 경우
  5. 애니메이션이나 트랜지션 효과

8장 상태 관리 및 폼 처리와의 연결

 7장의 클라이언트 컴포넌트 개념은 8장의 상태 관리 및 폼 처리와 직접적으로 연결됩니다. 클라이언트 컴포넌트에서 상태를 관리하고 폼 입력을 처리하는 방법을 배우게 되며, 이는 더 복잡한 상태 관리 라이브러리나 폼 라이브러리의 사용으로 확장됩니다.

실습 : 대화형 폼 구현

 다음 요구사항을 만족하는 대화형 폼을 클라이언트 컴포넌트로 구현해보세요.

  1. 사용자 이름, 이메일, 비밀번호 입력 필드
  2. 실시간 입력 유효성 검사
  3. 제출 버튼과 제출 처리 함수
  4. 폼 제출 후 성공 메시지 표시
구현 예시
'use client'
 
import { useState } from 'react'
 
export default function RegistrationForm() {
  const [formData, setFormData] = useState({
    username: '',
    email: '',
    password: ''
  })
  const [errors, setErrors] = useState({})
  const [isSubmitted, setIsSubmitted] = useState(false)
 
  const validateForm = () => {
    let newErrors = {}
    if (!formData.username) newErrors.username = 'Username is required'
    if (!formData.email.includes('@')) newErrors.email = 'Invalid email address'
    if (formData.password.length < 6) newErrors.password = 'Password must be at least 6 characters'
    setErrors(newErrors)
    return Object.keys(newErrors).length === 0
  }
 
  const handleChange = (e) => {
    const { name, value } = e.target
    setFormData(prev => ({ ...prev, [name]: value }))
  }
 
  const handleSubmit = (e) => {
    e.preventDefault()
    if (validateForm()) {
      // Here you would typically send the data to a server
      console.log('Form submitted:', formData)
      setIsSubmitted(true)
    }
  }
 
  if (isSubmitted) {
    return <div>Thank you for registering!</div>
  }
 
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor="username">Username:</label>
        <input
          type="text"
          id="username"
          name="username"
          value={formData.username}
          onChange={handleChange}
        />
        {errors.username && <p className="error">{errors.username}</p>}
      </div>
      <div>
        <label htmlFor="email">Email:</label>
        <input
          type="email"
          id="email"
          name="email"
          value={formData.email}
          onChange={handleChange}
        />
        {errors.email && <p className="error">{errors.email}</p>}
      </div>
      <div>
        <label htmlFor="password">Password:</label>
        <input
          type="password"
          id="password"
          name="password"
          value={formData.password}
          onChange={handleChange}
        />
        {errors.password && <p className="error">{errors.password}</p>}
      </div>
      <button type="submit">Register</button>
    </form>
  )
}

 이 실습을 통해 클라이언트 컴포넌트에서 상태 관리, 사용자 입력 처리, 폼 유효성 검사 등을 구현하는 방법을 경험할 수 있습니다. 이는 실제 애플리케이션에서 자주 사용되는 패턴으로, 클라이언트 사이드 상호작용의 핵심을 이해하는 데 도움이 됩니다.