티스토리 뷰
React를 공부할 때 가장 먼저 배우는 Hook이 보통 useState입니다. 그런데 문법은 짧아 보여도 막상 직접 쓰기 시작하면 “값은 왜 바로 안 바뀌지?”, “배열은 어떻게 추가하지?”, “객체는 왜 일부만 바꿨는데 이상하게 동작하지?” 같은 질문이 금방 생깁니다.
특히 입문 단계에서는 아래 포인트에서 많이 헷갈립니다.
- useState는 정확히 무엇을 하는가?
- 일반 변수와 state는 무엇이 다른가?
- 숫자/문자열은 어떻게 바꾸고, 배열·객체는 어떻게 업데이트하는가?
- 왜 기존 값을 직접 수정하면 안 되는가?
이번 글에서는 React 입문자가 가장 자주 찾는 useState 사용법 정리를 기준으로, 상태 관리 개념 → 값 변경 → 배열 업데이트 → 객체 업데이트 → 자주 하는 실수까지 한 번에 정리하겠습니다.
일반 JavaScript 변수는 값이 바뀌어도 React 화면이 자동으로 다시 그려지지 않습니다. 반면 useState로 관리하는 값은 바뀌면 React가 다시 렌더링하면서 화면도 함께 업데이트됩니다.
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>증가</button>
</div>
);
}
여기서 count는 현재 상태 값이고, setCount는 그 값을 바꾸는 함수입니다.
useState는 화면과 연결된 값을 관리하고, setter 함수는 그 값을 React 방식으로 바꾸는 통로입니다.
즉 useState를 쓰는 이유는 단순 저장이 아니라 변화하는 값을 화면과 연결하기 위해서입니다.
const [count, setCount] = useState(0);
<button onClick={() => setCount(count + 1)}>증가</button>
const [name, setName] = useState('Ace');
<button onClick={() => setName('React')}>이름 변경</button>
const [isOpen, setIsOpen] = useState(false);
<button onClick={() => setIsOpen(!isOpen)}>
{isOpen ? '닫기' : '열기'}
</button>
배열 state를 다룰 때 가장 많이 하는 실수는 기존 배열을 직접 바꾸는 것입니다.
const [todos, setTodos] = useState(['공부', '운동']);
// 좋은 방식
setTodos([...todos, '독서']);
자주 쓰는 패턴은 아래와 같습니다.
// 삭제
setTodos(todos.filter((todo) => todo !== '운동'));
// 수정
setTodos(todos.map((todo) =>
todo === '공부' ? 'React 공부' : todo
));
배열 state는 기존 배열을 직접 바꾸지 말고, 새 배열을 만들어 교체하는 방식으로 다뤄야 합니다.
// 피해야 할 방식
items.push('새 항목');
setItems(items);
const [user, setUser] = useState({ name: 'Ace', age: 28 });
setUser({
...user,
age: 29,
});
- state는 setter 함수로 바꿨는지 확인
- 배열은
map,filter, spread 문법으로 새 배열을 만들었는지 확인 - 객체는
...기존객체로 복사 후 필요한 값만 바꿨는지 확인 - 기존 값을 직접 수정하고 있지 않은지 확인
const [form, setForm] = useState({
email: '',
password: '',
});
const handleEmailChange = (e) => {
setForm({
...form,
email: e.target.value,
});
};
이 방식의 핵심은 기존 객체 전체를 복사한 뒤, 바꾸고 싶은 속성만 새 값으로 덮는 것입니다.
즉 객체 state를 다룰 때는 일부만 바꾸는 것처럼 보여도 실제로는 새 객체를 만드는 것이라고 이해하면 됩니다.
- useState는 화면과 연결된 값을 관리하는 Hook입니다.
- 값 변경은 setter 함수로 해야 합니다.
- 배열과 객체는 직접 수정하지 말고 새 값으로 교체해야 합니다.
- React에서는 "값을 수정"보다 "새 값을 만들어 교체"한다는 감각이 중요합니다.
- Q. useState 값은 왜 바로 안 바뀌는 것처럼 보이나요?
→ state 업데이트는 렌더링 흐름 안에서 반영되기 때문에, 호출 직후 바로 일반 변수처럼 바뀌는 감각과는 다르게 느껴질 수 있습니다. - Q. 배열에 push를 쓰면 왜 안 좋나요?
→ push는 기존 배열 자체를 바꾸기 때문에 React가 변경을 감지하는 방식과 잘 맞지 않습니다. 새 배열을 만들어 넣는 편이 안전합니다. - Q. 객체 state를 일부만 바꾸고 싶은데 꼭 spread를 써야 하나요?
→ 대부분의 경우 기존 객체를 유지하면서 일부 속성만 바꾸기 위해 spread 문법을 자주 씁니다.
React의 useState는 처음엔 단순한 Hook처럼 보이지만, 실제로는 React 상태 관리의 가장 기초를 이루는 개념입니다.
- 화면과 연결된 값을 관리하고
- setter 함수로 새 값을 넣고
- 배열과 객체는 직접 수정하지 않고 새 값으로 교체한다
이 흐름만 제대로 이해해도 React 입문 단계에서 가장 많이 하는 실수를 크게 줄일 수 있습니다.
특히 useState를 잘 쓰려면 문법보다 "이 값이 화면에 영향을 주는가?"와 "기존 값을 직접 바꾸지 않고 새 값으로 교체했는가?"를 먼저 점검하는 습관이 중요합니다.
useState는 값을 저장하는 Hook이 아니라, 화면과 연결된 상태를 React 방식으로 관리하는 Hook입니다.
※ 이 글은 React useState를 처음 이해하기 위한 입문 가이드입니다. 실제 프로젝트에서는 여러 state 조합, derived state, 상태 분리 기준, 전역 상태 관리와의 연결까지 함께 보면 더 좋습니다.
'Front > React' 카테고리의 다른 글
| React API 연동 방법 | Axios로 GET, POST 요청하고 화면에 출력하기 (1) | 2026.04.06 |
|---|---|
| React useEffect 사용법 정리 | 실행 시점, 의존성 배열, API 호출까지 (0) | 2026.04.03 |
| React 리눅스 서버 배포 방법 | build 파일 업로드부터 실제 서비스 적용까지 (0) | 2026.04.03 |
| React Router 사용법 | 페이지 이동, Link, 기본 라우팅 적용 방법 (2) | 2026.04.02 |
| React JSX 문법 정리 | 기본 문법, 조건부 렌더링, 리스트 렌더링까지 (0) | 2026.04.02 |

