plogger

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>
}