리액트 훅 | useState에 대해 알아보기

2025. 8. 8. 20:09·FRONTEND/React

0. 리액트 훅이란?

리액트가 제공하는 미리 만들어둔 도구로,

함수형 컴포넌트에서 상태(state)와 리액트의 다양한 기능을

간단한 함수 호출로 사용할 수 있게 해주는 함수입니다.

 

훅(hook)이 왜 생겨났을까?

리액트 16.8 이전에는 클래스 컴포넌트에서만 상태(state)나 생명주기(lifecycle) 기능을 사용할 수 있었습니다.

이 방식에는 다음과 같은 한계가 존재했습니다.

- this 바인딩 문제 : 클래스 메서드에서 this가 의도치 않게 바뀌어 버리는 문제가 잦음

 

- 상태 로직이 분산 : 하나의 기능과 관련된 코드가 componentDidMount, componentDidUpdate, componentWillUnmount 등에 흩어짐

- 재사용성 부족 : 클래스 간 상태 로직을 재사용하려면 HOC, render props 등 복잡한 패턴 필요

 

 

상태 관리 예시 : 클래스 방식

import React, { Component } from 'react';

class Counter extends Component {
  // 1. state : 클래스의 속성으로 정의
  state = {
    count: 0
  };

  // 2. 상태 변경 : setState 메서드 사용
  increase = () => {
    this.setState({ count: this.state.count + 1 });
  };

  render() {
    return (
      <div>
        <p>카운트: {this.state.count}</p>
        <button onClick={this.increase}>+1</button>
      </div>
    );
  }
}

- this.state로 읽고, this.setState()로 변경

- this 바인딩 문제와 긴 코드로 인한 가독성 저하 발생

 

그렇다면 훅 등장 이후 어떻게 바뀌었을까요 ?

import React, { useState } from 'react';

function Counter() {
  // count : 현재 상태 값
  // setCount : 상태 변경 함수
  const [count, setCount] = useState(0); // 초기값 0
  const increase = () => setCount(count + 1);

  return (
    <div>
      <p>카운트 : {count}</p>
      <button onClick={increase}>+1</button>
    </div>
  );
}

export default Counter;

- this 없이 간결한 코드

- 관련 있는 로직을 하나의 함수 안에서 묶어 관리 용이

훅 사용 전 (클래스) 훅 사용 후 (함수형)
state = { count: 0} useState(0)
this.state.count count
this.setState({ count: ... }) setCount(...)
this 바인딩 필요 this 대신 화살표 함수 사용

 

훅을 사용하면 클래스 문법 없이도 상태 관리가 가능하고,

짧고 직관적인 코드로 로직을 재사용하고 구성할 수 있습니다.

 

1. useState란?

리액트 훅 중 가장 기본이 되는 훅인 useState는

함수형 컴포넌트에서 변하는 값(상태)을 저장하고 관리하는 기능을 제공합니다.

값이 변하면 컴포넌트가 다시 렌더링 되어 UI에 반영됩니다.

 

기본 문법

const [state, setState] = useState(initialValue);

- state : 현재 상태 값 (읽기 전용)

- setState : 상태를 변경하는 함수 (호출 시 렌더링 발생)

- initialValue : 초깃값 (첫 렌더에서만 사용)

 

2. 기본 동작 원리

(1) 상태 저장

: state는 컴포넌트 내부의 리액트 상태 저장소에 기록됩니다.

(2) 상태 변경

: setState를 호출하면 리액트가 변경 예약을 걸고, 불필요한 렌더링을 방지하기 위해 최적화합니다.

(3) UI 갱신

: 다음 렌더링 주기에 새로운 state 값이 UI에 반영됩니다.

 

3. 예시

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0); // 초기값 0

  const increase = () => setCount(count + 1);

  return (
    <div>
      <p>카운트: {count}</p>
      <button onClick={increase}>+1</button>
    </div>
  );
}

4. 알아야 할 핵심 개념

4-1. 상태 변경은 비동기적

setCount(count + 1);
console.log(count); // 여전히 이전 값일 수 있음

이유 : 리액트는 성능 최적화를 위해서 여러 상태 변경을 묶어서(batching) 처리

setCount(prev => prev + 1);

해결 : 이전 값 기반으로 변경 시 업데이터 함수 사용

 

4-2. 불변성 유지

- 객체/배열 상태를 다룰 때는 원본을 수정하지 말고 새로운 값을 만들어야 합니다.

// 잘못된 예시
todos.push('리액트공부');
setTodos(todos);

// 올바른 예시
setTodos(prev => [...prev, '리액트공부']);

이유 : 리액트는 참조 비교(얕은 비교, shallow compare)로 변경 여부를 판단합니다.

-> 참조가 바뀌어야 감지 가능 !

 

4-3. 초기값은 첫 렌더에만 적용

- useState(initialValue)의 초기값은 컴포넌트 첫 실행 시만 반영됩니다.

- props에 따라 상태 초기화하려면 useEffect로 처리합니다.

 

4-4. 지연 초기화(Lazy Initialization)

- 초기값 계산이 무거울 때, 함수 형태로 전달하면 첫 렌더에서만 실행합니다.

const [data, setData] = useState(() => heavyCalculation());

-> 첫 렌더에서만 실행되고 이후에는 재계산하지 않음

 

 

4-5. 값 덮어쓰기

- setState는 병합이 아니라 교체

- 객체 상태를 업데이트할 때는 기존 값 복사 후 변경

setUser(prev => ({ ...prev, age: 25 }));

 

5. 자주 쓰는 패턴 알아보기

5-1. 토글

const [isOpen, setIsOpen] = useState(false);
const toggle = () => setIsOpen(prev => !prev);

5-2. 폼 입력

const [form, setForm] = useState({ name: '', email: '' });
const handleChange = e => {
  const { name, value } = e.target;
  setForm(prev => ({ ...prev, [name]: value }));
};

5-3. 배열 관리

const [items, setItems] = useState([]);
setItems(prev => [...prev, newItem]); // 추가
setItems(prev => prev.filter(item => item.id !== id)); // 삭제

 

마무리

마지막으로 놓치기 쉬운 부분을 한번 더 살펴보며 마무리하겠습니다.
1. 훅은 컴포넌트 최상위에서만 호출 (조건문이나 반복문 안 X)
2. 동일 값 setState 시 렌더링이 되지 않는다 -> 리액트는 참조 비교로 최적화하기 때문
3. 배열, 객체 상태를 한꺼번에 묶기보다 분리해서 관리 -> 불필요한 렌더를 방지하기 위해서

'FRONTEND > React' 카테고리의 다른 글

리액트 훅 | useCallback에 대해 알아보기  (8) 2025.08.12
리액트 훅 | useEffect에 대해 알아보기  (5) 2025.08.11
부모 요소 패딩 값에 영향을 받지 않고 전체 너비 구분선 그리기  (0) 2025.04.04
모던 리액트 Deep Dive | 1.1 자바스크립트와 동등 비교  (0) 2025.03.09
리액트 훅(React Hook) 이해하기  (1) 2025.01.19
'FRONTEND/React' 카테고리의 다른 글
  • 리액트 훅 | useCallback에 대해 알아보기
  • 리액트 훅 | useEffect에 대해 알아보기
  • 부모 요소 패딩 값에 영향을 받지 않고 전체 너비 구분선 그리기
  • 모던 리액트 Deep Dive | 1.1 자바스크립트와 동등 비교
uoaheu
uoaheu
uoaheu 님의 블로그 입니다.
  • uoaheu
    uoaheu 님의 블로그
    uoaheu
  • 전체
    오늘
    어제
    • 분류 전체보기 (50)
      • 알고리즘 (7)
      • CS (9)
      • FRONTEND (9)
        • React (12)
        • Kotlin (1)
        • JS (5)
        • HTML (2)
      • SQL (2)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    멀티캠퍼스it부트캠프
    BFS
    toss uiux
    토스분석
    토스 uiux
    토스 앱 분석
    toss 분석
    백준1926번
    mysql 피벗테이블
    이더넷프레임
    혼자서 공부하는 네트워크
    useactionstate
    알고리즘
    리액트usestate
    엘지유플러스유레카프론트엔드
    유레카3기
    mysql
    부트캠프후기
    mysql로 피벗테이블만들기
    boj25418
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
uoaheu
리액트 훅 | useState에 대해 알아보기
상단으로

티스토리툴바