클라이언트 컴포넌트 사용법
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>
)
}
이 지시어는 해당 파일과 그 하위에서 임포트하는 모든 모듈이 클라이언트 번들에 포함되도록 합니다.
클라이언트 컴포넌트의 특징
- 브라우저 API 접근 : window, document 등의 브라우저 API를 사용할 수 있습니다.
- 상태 관리 : React의 useState, useReducer 등을 사용할 수 있습니다.
- 이벤트 리스너 : onClick, onChange 등의 이벤트를 처리할 수 있습니다.
- 생명주기 메서드 : useEffect, useLayoutEffect 등을 사용할 수 있습니다.
- 클라이언트 사이드 라우팅 : 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>
}
2. 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>
)
}
클라이언트 컴포넌트의 적절한 사용 사례
- 사용자 입력 처리가 필요한 폼
- 클릭, 스크롤 등의 상호작용이 필요한 UI 요소
- 브라우저 API를 사용해야 하는 기능 (예 : geolocation)
- 클라이언트 사이드 상태 관리가 필요한 경우
- 애니메이션이나 트랜지션 효과
8장 상태 관리 및 폼 처리와의 연결
7장의 클라이언트 컴포넌트 개념은 8장의 상태 관리 및 폼 처리와 직접적으로 연결됩니다.
클라이언트 컴포넌트에서 상태를 관리하고 폼 입력을 처리하는 방법을 배우게 되며, 이는 더 복잡한 상태 관리 라이브러리나 폼 라이브러리의 사용으로 확장됩니다.
실습 : 대화형 폼 구현
다음 요구사항을 만족하는 대화형 폼을 클라이언트 컴포넌트로 구현해보세요.
- 사용자 이름, 이메일, 비밀번호 입력 필드
- 실시간 입력 유효성 검사
- 제출 버튼과 제출 처리 함수
- 폼 제출 후 성공 메시지 표시
'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>
)
}
이 실습을 통해 클라이언트 컴포넌트에서 상태 관리, 사용자 입력 처리, 폼 유효성 검사 등을 구현하는 방법을 경험할 수 있습니다.
이는 실제 애플리케이션에서 자주 사용되는 패턴으로, 클라이언트 사이드 상호작용의 핵심을 이해하는 데 도움이 됩니다.