React Hooks 핵심 정리 — useState, useEffect, useRef, useMemo
useState — 상태 관리
import { useState } from 'react'
function Counter() {
const [count, setCount] = useState(0)
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(prev => prev + 1)}>+1</button>
</div>
)
}
이전 값을 기반으로 업데이트할 때는 항상 함수형 업데이트(
prev =>)를 사용하세요.
useEffect — 사이드 이펙트
import { useState, useEffect } from 'react'
function UserProfile({ userId }) {
const [user, setUser] = useState(null)
useEffect(() => {
fetch(`/api/users/${userId}`)
.then(res => res.json())
.then(data => setUser(data))
// 클린업 함수 — 컴포넌트 언마운트 시 실행
return () => {
// 구독 해제, 타이머 정리 등
}
}, [userId]) // userId가 바뀔 때마다 재실행
return <div>{user?.name}</div>
}
| 의존성 배열 | 실행 시점 |
|---|---|
| 없음 | 매 렌더링마다 |
[] | 최초 마운트 1회만 |
[value] | value가 변경될 때마다 |
useRef — DOM 참조 및 값 유지
import { useRef } from 'react'
function TextInput() {
const inputRef = useRef(null)
function focusInput() {
inputRef.current.focus()
}
return (
<>
<input ref={inputRef} />
<button onClick={focusInput}>포커스</button>
</>
)
}
useRef는 렌더링을 유발하지 않고 값을 유지할 때도 사용합니다.
useMemo — 계산 결과 캐싱
import { useMemo } from 'react'
function ProductList({ products, filterText }) {
const filtered = useMemo(
() => products.filter(p => p.name.includes(filterText)),
[products, filterText] // 이 값이 바뀔 때만 재계산
)
return <ul>{filtered.map(p => <li key={p.id}>{p.name}</li>)}</ul>
}
useCallback — 함수 메모이제이션
import { useCallback } from 'react'
function Parent() {
const handleClick = useCallback((id) => {
console.log('clicked:', id)
}, []) // 의존성 없으면 최초 1회만 생성
return <Child onClick={handleClick} />
}
커스텀 Hook 만들기
반복되는 로직을 추출해 재사용합니다.
// hooks/useFetch.js
import { useState, useEffect } from 'react'
export function useFetch(url) {
const [data, setData] = useState(null)
const [loading, setLoading] = useState(true)
const [error, setError] = useState(null)
useEffect(() => {
setLoading(true)
fetch(url)
.then(res => res.json())
.then(data => { setData(data); setLoading(false) })
.catch(err => { setError(err); setLoading(false) })
}, [url])
return { data, loading, error }
}
// 사용
function Posts() {
const { data, loading, error } = useFetch('/api/posts')
if (loading) return <p>로딩 중...</p>
if (error) return <p>오류 발생</p>
return <ul>{data.map(p => <li key={p.id}>{p.title}</li>)}</ul>
}