useState — 가장 많이 쓰는 훅, 이것만 알면 절반은 끝납니다
Article
앞에서 상태(State)가 뭔지 알아봤습니다. 이제 실제로 상태를 만들고 사용하는 방법을 배울 차례입니다.
React에서 상태를 사용하려면 useState라는 훅(Hook)을 씁니다. React에서 가장 많이 쓰이는 기능이고, 이것만 제대로 알아도 절반은 해결됩니다.
기본 사용법
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
}
이 코드에서 버튼을 누르면 화면의 숫자가 실제로 올라갑니다. 앞에서 let으로는 안 되던 게, useState로는 되는 겁니다.
구조를 뜯어보겠습니다
const [count, setCount] = useState(0);
이 한 줄이 핵심입니다. 하나씩 살펴보겠습니다.
useState(0): 초기값이 0인 상태를 만듭니다.count: 현재 상태 값입니다. 화면에 보여줄 때 이 값을 씁니다.setCount: 상태를 바꾸는 함수입니다. 이걸 호출해야 화면이 업데이트됩니다.
이 구조를 배열 구조 분해라고 합니다. useState가 배열 두 개를 돌려주는데, 첫 번째가 값이고 두 번째가 변경 함수입니다.
이름은 자유롭게 지을 수 있지만, 관례적으로 [값, set값] 형태로 짓습니다.
const [name, setName] = useState("민수");
const [isOpen, setIsOpen] = useState(false);
const [items, setItems] = useState([]);
왜 직접 수정하지 않고 setter를 쓸까요
"그냥 count = 1이라고 쓰면 안 되나요?"
안 됩니다. 이유는 간단합니다. React가 변경을 감지하지 못하기 때문입니다.
setCount를 호출해야 React가 "아, 값이 바뀌었구나. 화면을 다시 그려야겠다"고 인식합니다. 직접 대입하면 React는 아무것도 모릅니다.
택배 비유로 설명하면, setCount는 배송 알림이 포함된 택배입니다. 물건이 도착하면 알림이 오니까 확인할 수 있습니다. 반면 직접 대입은 알림 없이 몰래 놓고 가는 택배입니다. 아무도 모릅니다.
카운터 예시
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>현재 값: {count}</p>
<button onClick={() => setCount(count + 1)}>증가</button>
<button onClick={() => setCount(count - 1)}>감소</button>
<button onClick={() => setCount(0)}>초기화</button>
</div>
);
}
버튼마다 setCount에 다른 값을 넘겨주면 됩니다. 간단합니다.
토글 예시
function Toggle() {
const [isOn, setIsOn] = useState(false);
return (
<button onClick={() => setIsOn(!isOn)}>
{isOn ? "켜짐" : "꺼짐"}
</button>
);
}
true와 false를 왔다 갔다 하는 토글도 useState 하나면 충분합니다.
주의할 점
상태 업데이트는 비동기입니다
setCount(count + 1);
console.log(count); // 아직 이전 값이 찍힙니다
setCount를 호출한 직후에 count를 확인하면 아직 이전 값입니다. 상태 업데이트는 즉시 반영되지 않고, React가 다음 렌더링 때 반영합니다.
이전 값을 기반으로 업데이트할 때
// 이렇게 하면 문제가 생길 수 있습니다
setCount(count + 1);
setCount(count + 1); // 두 번 호출해도 1만 올라갑니다
// 이렇게 하면 안전합니다
setCount((prev) => prev + 1);
setCount((prev) => prev + 1); // 정확히 2가 올라갑니다
setCount에 값 대신 함수를 넘기면, 항상 최신 값을 기준으로 업데이트됩니다. 연속으로 업데이트해야 할 때는 이 방식을 쓰는 게 안전합니다.
정리
- **
useState**는 상태를 만드는 함수입니다. [값, 변경함수]구조로 사용합니다.- 상태를 바꿀 때는 반드시 **변경함수(setter)**를 씁니다.
- 상태 업데이트는 비동기로 동작합니다.
- 이전 값 기반 업데이트는 함수형 업데이트가 안전합니다.
useState만 익숙해져도 대부분의 인터랙션을 구현할 수 있습니다. 다음 글에서는 화면이 그려진 후 실행할 작업을 관리하는 useEffect를 알아보겠습니다.