모든 강의를 무료로 볼 수 있어요. 회원가입 없이도 학습 가능합니다.

6강 / 전체 30강

State와 useState

4분 읽기 조회 53

State의 본질과 useState 훅의 동작 원리, 상태 변경이 리렌더링을 어떻게 일으키는지, 그리고 불변성 원칙을 왜 지켜야 하는지 깊이 이해합니다.

💡 State란 무엇인가 — Props와 무엇이 다른가

Props는 부모가 자식에게 넘겨주는 읽기 전용 데이터입니다. 그렇다면 컴포넌트 자신이 가지고 있고, 시간에 따라 변하는 데이터는 어떻게 관리할까요? 이것이 State(상태)입니다.

State와 Props의 차이:

구분PropsState
출처부모 컴포넌트컴포넌트 자신
수정읽기 전용setState 함수로 변경
목적외부에서 설정값 전달컴포넌트 내부의 변하는 값
예시버튼 텍스트, 색상클릭 횟수, 입력값, 열림/닫힘

⚙️ useState 훅 — 문법과 동작 원리

useState는 리액트가 제공하는 훅(Hook)입니다. 훅은 함수 컴포넌트에서 리액트 기능을 사용하게 해주는 특별한 함수입니다.

import { useState } from 'react'

function Counter() {
  // [현재값, 업데이트 함수] = useState(초기값)
  const [count, setCount] = useState(0)

  return (
    <div>
      <p>현재 값: {count}</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
      <button onClick={() => setCount(count - 1)}>-1</button>
      <button onClick={() => setCount(0)}>초기화</button>
    </div>
  )
}

useState(0)는 배열을 반환합니다. 첫 번째 요소는 현재 상태값(count), 두 번째 요소는 상태를 업데이트하는 함수(setCount)입니다. 구조 분해로 이름을 붙여 사용합니다.

🔄 리렌더링의 작동 방식

setCount를 호출하면 무슨 일이 일어날까요? 리액트의 핵심 동작 흐름:

  1. setCount(count + 1) 호출
  2. 리액트가 새 상태값(count + 1)을 기록
  3. 컴포넌트 함수를 다시 실행(리렌더링)
  4. 새로운 JSX를 만들어 이전 JSX와 비교(Virtual DOM diffing)
  5. 변경된 부분만 실제 DOM에 반영

중요한 점: 상태가 변하면 컴포넌트 함수 전체가 다시 실행됩니다. 하지만 DOM은 변경된 부분만 업데이트됩니다. 이것이 리액트가 효율적인 이유입니다.

function Counter() {
  const [count, setCount] = useState(0)
  console.log('렌더링 실행됨, count:', count)  // 클릭할 때마다 출력됨

  return (
    <button onClick={() => setCount(count + 1)}>
      {count}번 클릭
    </button>
  )
}

⚠️ 불변성 원칙 — 왜 직접 수정하면 안 되는가

상태를 업데이트할 때 직접 수정하면 절대 안 됩니다. 특히 배열이나 객체 상태에서 자주 실수합니다.

const [items, setItems] = useState(['사과', '바나나'])

// ❌ 직접 수정 — 리렌더링이 일어나지 않음!
function addItem() {
  items.push('딸기')  // 원본 배열을 변경했지만
  setItems(items)      // 같은 배열 참조라 리액트가 변화를 감지 못함
}

// ✅ 새 배열을 만들어 교체 (불변성 유지)
function addItem() {
  setItems([...items, '딸기'])  // 스프레드로 새 배열 생성
}

// ✅ 객체 상태도 마찬가지
const [user, setUser] = useState({ name: '김민준', age: 25 })

// ❌ 직접 수정 금지
user.age = 26
setUser(user)

// ✅ 새 객체 생성
setUser({ ...user, age: 26 })

리액트는 참조(reference)를 비교해서 변화를 감지합니다. 같은 배열/객체를 수정하면 참조가 바뀌지 않아 리액트가 변화를 못 보고 리렌더링이 일어나지 않습니다.

🔀 함수형 업데이트

다음 상태가 이전 상태에 의존할 때는 함수형 업데이트를 사용하세요. 연속 클릭 같은 상황에서 정확한 값을 보장합니다:

// ❌ 배치 처리 시 문제 발생 가능
const increment = () => setCount(count + 1)

// ✅ 이전 값을 인수로 받는 형태
const increment = () => setCount(prev => prev + 1)

✅ 정리

  • State는 컴포넌트 자신이 가지는 변할 수 있는 값입니다.
  • useState(초기값)는 [현재값, setter함수]를 반환합니다.
  • setter를 호출하면 컴포넌트가 리렌더링됩니다.
  • 배열·객체는 직접 수정하지 말고 새 것을 만들어 교체하세요 (불변성).
  • 이전 값 기반으로 업데이트할 때는 setCount(prev => prev + 1) 형태를 사용하세요.

관련 주제

  • useState 훅
  • 상태와 리렌더링
  • 불변성 원칙
  • state vs props
  • 개발·프로그래밍
  • 개발·프로그래밍 강의
  • 리액트 입문 — 컴포넌트로 만드는 웹
  • 무료강의
  • 무료 온라인 강의
  • NUGUNA
  • 누구나

📚 시리즈 전체 공유

리액트 입문 — 컴포넌트로 만드는 웹

이 강의가 속한 시리즈는 총 30강, 모두 무료입니다. 처음부터 배우려는 동료에게 시리즈 전체를 알려 주세요.

댓글

0/1000

불러오는 중...