[이제와서 시작하는 React 마스터하기 #3] useState - 화면을 움직이게 만들기
이 포스트를 읽고 나면 ✅ useState가 무엇인지 이해할 수 있어요 ✅ 버튼 클릭으로 화면을 바꿀 수 있어요 ✅ 인터랙티브한 React 앱을 만들 수 있어요
📚 시작하기 전에
이전 포스트 Day 2: 첫 React 앱 만들어보기에서 React 앱을 만들고 JSX로 화면을 그렸어요.
하지만 화면이 고정되어 있었죠? 버튼을 눌러도 아무 일도 일어나지 않았어요.
오늘은 화면을 움직이게 만들 거예요! 🚀
준비물
- 지난 시간에 만든 React 프로젝트
- 또는 새 프로젝트:
npm create vite@latest my-app -- --template react
🤔 State가 뭐예요?
“State”는 상태를 뜻해요.
쉽게 말하면:
- 화면에 보여줄 변하는 데이터
- 사용자가 클릭하거나 입력하면 바뀌는 값
예를 들어볼까요?
일상 생활의 State
1
2
3
4
5
6
7
8
9
10
11
전등 스위치:
- State: 켜짐(ON) 또는 꺼짐(OFF)
- 버튼을 누르면 → State가 바뀜 → 불이 켜지거나 꺼짐
좋아요 버튼:
- State: 좋아요 개수 (0, 1, 2, 3...)
- 클릭하면 → State가 바뀜 → 숫자가 증가
로그인 상태:
- State: 로그인됨(true) 또는 로그아웃(false)
- 로그인하면 → State가 바뀜 → 화면이 바뀜
React에서 이런 “변하는 값”을 관리하는 도구가 useState예요!
🎯 useState 첫 만남
가장 간단한 예제: 카운터
코드를 보기 전에, 뭘 만들 건지 먼저 알아볼게요:
1
2
화면에 숫자가 보여요: 0
버튼을 클릭하면 → 숫자가 1씩 증가해요
코드 작성하기
src/App.jsx 파일을 열고 다음과 같이 작성하세요:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { useState } from 'react';
function App() {
// useState 사용하기
const [count, setCount] = useState(0);
return (
<div style={{ padding: '20px' }}>
<h1>카운터</h1>
<p>현재 숫자: {count}</p>
<button onClick={() => setCount(count + 1)}>
+1 증가
</button>
</div>
);
}
export default App;
결과 확인
파일을 저장하고 브라우저를 확인하세요!
버튼을 클릭하면 숫자가 증가하나요? 🎉
축하합니다! 첫 인터랙티브 React 앱을 만들었어요!
🔍 코드 이해하기
코드를 한 줄씩 뜯어볼게요.
1단계: useState import하기
1
import { useState } from 'react';
React에서 useState를 가져와요. 이게 없으면 useState를 쓸 수 없어요!
2단계: useState 사용하기
1
const [count, setCount] = useState(0);
이 한 줄이 매우 중요해요! 하나씩 뜯어볼게요.
useState(0)
0: 초기값이에요 (처음에 화면에 보일 숫자)- 다른 값도 가능해요:
useState(10),useState(100)
[count, setCount]
count: 현재 값을 저장하는 변수setCount: 값을 바꾸는 함수
비유로 이해하기:
1
2
3
4
5
6
7
useState는 상자를 하나 만들어요
[상자에 든 값, 값을 바꾸는 도구] = useState(초기값)
[count, setCount] = useState(0)
count → 상자를 열어서 안에 든 숫자를 확인
setCount → 상자에 새 숫자를 넣기
3단계: 화면에 표시하기
1
<p>현재 숫자: {count}</p>
count 변수를 중괄호 {}로 감싸서 화면에 보여줘요.
4단계: 버튼 클릭 시 값 바꾸기
1
2
3
<button onClick={() => setCount(count + 1)}>
+1 증가
</button>
onClick: 버튼을 클릭하면 실행할 코드() =>: 화살표 함수 (함수를 간단히 쓰는 방법)setCount(count + 1): 현재 값에 1을 더한 값으로 바꾸기
💪 실습 1: 감소 버튼 추가하기
이제 여러분 차례예요!
해보기
현재 코드에 “감소” 버튼을 추가해보세요.
힌트:
+1 증가버튼을 복사해서 수정하세요count + 1대신count - 1을 써보세요
💡 정답 확인
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function App() {
const [count, setCount] = useState(0);
return (
<div style={{ padding: '20px' }}>
<h1>카운터</h1>
<p>현재 숫자: {count}</p>
<button onClick={() => setCount(count + 1)}>
+1 증가
</button>
<button onClick={() => setCount(count - 1)}>
-1 감소
</button>
<button onClick={() => setCount(0)}>
초기화
</button>
</div>
);
}
보너스: 초기화 버튼도 추가했어요!
💪 실습 2: 입력 폼 만들기
카운터는 숫자만 다뤘어요. 이번엔 문자열을 다뤄볼까요?
목표
1
2
입력창에 이름을 입력하면
→ 아래에 "안녕하세요, [이름]님!"이 실시간으로 보여요
따라하기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import { useState } from 'react';
function App() {
const [name, setName] = useState('');
return (
<div style={{ padding: '20px' }}>
<h1>이름 입력</h1>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="이름을 입력하세요"
/>
<p>안녕하세요, {name}님!</p>
</div>
);
}
export default App;
새로운 포인트
value={name}
- input의 값을
namestate와 연결해요
onChange={(e) => setName(e.target.value)}
- input에 타이핑할 때마다 실행돼요
e.target.value: 사용자가 입력한 값setName(...): 그 값으로 state를 업데이트
실시간으로 화면이 바뀌는 이유:
- 사용자가 타이핑 →
onChange실행 setName으로 state 변경- React가 자동으로 화면 다시 그리기 (re-render)
- 새로운 값이 화면에 보임
💪 실습 3: 여러 개의 State 사용하기
하나의 컴포넌트에서 여러 개의 state를 쓸 수 있어요!
따라하기
로그인 폼을 만들어봐요:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import { useState } from 'react';
function App() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [message, setMessage] = useState('');
const handleLogin = () => {
if (email && password) {
setMessage(`${email}으로 로그인 시도 중...`);
} else {
setMessage('이메일과 비밀번호를 입력하세요!');
}
};
return (
<div style={{ padding: '20px' }}>
<h1>로그인</h1>
<div style={{ marginBottom: '10px' }}>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="이메일"
style={{ marginRight: '10px' }}
/>
</div>
<div style={{ marginBottom: '10px' }}>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="비밀번호"
/>
</div>
<button onClick={handleLogin}>
로그인
</button>
{message && (
<p style={{ marginTop: '10px', color: '#0066cc' }}>
{message}
</p>
)}
</div>
);
}
export default App;
포인트
여러 개의 useState:
1
2
3
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [message, setMessage] = useState('');
각 데이터마다 별도의 state를 만들어요!
함수로 로직 분리:
1
2
3
const handleLogin = () => {
// 로그인 로직
};
복잡한 코드는 함수로 빼면 깔끔해요!
💪 실습 4: 토글 버튼 만들기
on/off, 보이기/숨기기 같은 기능은 어떻게 만들까요?
따라하기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { useState } from 'react';
function App() {
const [isVisible, setIsVisible] = useState(true);
return (
<div style={{ padding: '20px' }}>
<h1>토글 버튼</h1>
<button onClick={() => setIsVisible(!isVisible)}>
{isVisible ? '숨기기' : '보이기'}
</button>
{isVisible && (
<p style={{ marginTop: '10px', padding: '10px', backgroundColor: '#f0f0f0' }}>
안녕하세요! 이 텍스트는 토글됩니다! 👋
</p>
)}
</div>
);
}
export default App;
새로운 개념
Boolean state:
1
const [isVisible, setIsVisible] = useState(true);
true 또는 false 값을 가지는 state예요!
NOT 연산자 !:
1
setIsVisible(!isVisible)
isVisible이true면 →false로 바꿈isVisible이false면 →true로 바꿈
삼항 연산자:
1
{isVisible ? '숨기기' : '보이기'}
조건 ? 참일때 : 거짓일때
조건부 렌더링:
1
{isVisible && <p>...</p>}
isVisible이 true일 때만 <p> 태그를 보여줘요!
⚠️ 자주 하는 실수
실수 1: State를 직접 바꾸려고 하기
1
2
3
4
5
6
7
8
const [count, setCount] = useState(0);
// ❌ 이렇게 하면 안 돼요!
count = count + 1; // 에러!
count++; // 에러!
// ✅ 반드시 set 함수를 사용하세요
setCount(count + 1); // 정답!
왜 그럴까요?
React는 setCount를 호출할 때만 “값이 바뀌었구나!” 하고 화면을 다시 그려요. 직접 바꾸면 React가 모르기 때문에 화면이 안 바뀌어요!
실수 2: set 함수 이름을 잘못 쓰기
1
2
3
4
5
6
7
// ❌ 이름이 일치하지 않아요
const [count, setNumber] = useState(0);
setNumber(count + 1); // 헷갈려요!
// ✅ 일관성 있게 지어요
const [count, setCount] = useState(0);
setCount(count + 1); // 명확해요!
규칙:
- 변수 이름:
count,name,isVisible - Set 함수:
setCount,setName,setIsVisible
실수 3: onChange 없이 value만 쓰기
1
2
3
4
5
6
7
8
// ❌ 입력이 안 돼요!
<input value={name} />
// ✅ onChange도 함께!
<input
value={name}
onChange={(e) => setName(e.target.value)}
/>
value만 있으면 입력창이 읽기 전용이 돼요! onChange로 값을 업데이트해야 입력할 수 있어요.
🎯 종합 실습: Todo 리스트 만들기
배운 내용을 모두 활용해서 간단한 Todo 앱을 만들어봐요!
기능
- 입력창에 할 일을 입력
- “추가” 버튼 클릭
- 아래에 목록으로 표시
- “삭제” 버튼으로 제거
코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import { useState } from 'react';
function App() {
const [todos, setTodos] = useState([]);
const [input, setInput] = useState('');
const addTodo = () => {
if (input.trim()) {
// 기존 배열에 새 항목 추가
setTodos([...todos, input]);
setInput(''); // 입력창 비우기
}
};
const deleteTodo = (index) => {
// 해당 인덱스 제거
const newTodos = todos.filter((_, i) => i !== index);
setTodos(newTodos);
};
return (
<div style={{ padding: '20px', maxWidth: '400px' }}>
<h1>할 일 목록 📝</h1>
<div style={{ marginBottom: '20px' }}>
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && addTodo()}
placeholder="할 일을 입력하세요"
style={{ padding: '5px', marginRight: '5px' }}
/>
<button onClick={addTodo}>추가</button>
</div>
<ul style={{ listStyle: 'none', padding: 0 }}>
{todos.map((todo, index) => (
<li
key={index}
style={{
padding: '10px',
marginBottom: '5px',
backgroundColor: '#f0f0f0',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center'
}}
>
<span>{todo}</span>
<button onClick={() => deleteTodo(index)}>
삭제
</button>
</li>
))}
</ul>
{todos.length === 0 && (
<p style={{ color: '#999' }}>할 일이 없습니다!</p>
)}
</div>
);
}
export default App;
새로운 개념
배열 State:
1
const [todos, setTodos] = useState([]);
여러 개의 항목을 저장해요!
배열에 항목 추가:
1
setTodos([...todos, input]);
...todos: 기존 배열의 모든 항목 input: 새로 추가할 항목
배열에서 항목 제거:
1
const newTodos = todos.filter((_, i) => i !== index);
filter는 조건에 맞는 항목만 남겨요.
배열 렌더링:
1
2
3
{todos.map((todo, index) => (
<li key={index}>...</li>
))}
map으로 배열의 각 항목을 HTML로 변환해요.
📝 정리
자, Day 3을 마무리할 시간이에요!
오늘 배운 내용 체크리스트
- useState가 무엇인지 이해했어요
- state로 숫자를 관리할 수 있어요
- state로 문자열을 관리할 수 있어요
- 여러 개의 state를 사용할 수 있어요
- 배열 state를 다룰 수 있어요
- 간단한 Todo 앱을 만들었어요
핵심 요약 3줄
- useState: React에서 변하는 값을 관리하는 Hook
- 사용법:
const [값, set함수] = useState(초기값) - 규칙: 값을 바꿀 때는 반드시 set 함수 사용!
💪 숙제 (선택사항)
- 카운터 업그레이드
- +1, -1, +10, -10, 초기화 버튼 추가
- 숫자에 따라 색상 바꾸기 (양수는 파란색, 음수는 빨간색)
- 계산기 만들기
- 두 숫자를 입력받아요
- +, -, ×, ÷ 버튼으로 계산해요
- 결과를 보여줘요
- 좋아요 버튼 만들기
- 버튼을 누르면 좋아요 개수 증가
- 누른 상태면 빨간색 하트, 안 누르면 회색 하트
- 취소도 가능하게
🚀 다음 단계
축하합니다! useState를 마스터했어요! 🎉
이제 화면을 마음대로 움직일 수 있어요. 하지만 아직 한 가지 문제가 있어요.
“여러 컴포넌트 간에 데이터를 어떻게 공유하지?”
다음 포스트에서는 Props를 배워서 부모와 자식 컴포넌트 간에 데이터를 전달하는 방법을 알아볼 거예요!
➡️ Day 4: Props - 컴포넌트끼리 대화하기에서 만나요!
💬 State가 어렵게 느껴지나요?
처음엔 모두 그래요! “왜 변수를 그냥 안 쓰고 useState를 써야 해?”라고 생각할 수 있어요.
하지만 몇 번 써보면 이해가 돼요: React가 자동으로 화면을 업데이트하려면 state를 써야 해요!
코드를 직접 타이핑하고, 버튼을 눌러보고, 동작을 확인하세요. 눈으로 보면서 배우는 게 가장 빨라요! 💪
에러가 나도 괜찮아요. 에러 메시지를 읽고, 코드를 고쳐보세요. 그게 바로 성장하는 과정이에요! 🌱
🎓 시리즈 목록
Phase 1: React 기초 (Day 1-8)
- React, 왜 배워야 할까요?
- 첫 React 앱 만들어보기
- useState - 화면을 움직이게 만들기 (현재 포스트)
- Hooks 완벽 가이드
- 조건부 렌더링과 리스트 렌더링
- 컴포넌트 생명주기 이해하기
- Context API로 전역 상태 관리하기
- Custom Hooks 만들기
Phase 2: React 활용 (Day 9-14)
Phase 3: React 심화 (Day 15-20)
🔗 유용한 리소스
- React 공식 문서 - useState - useState 완벽 가이드
- React 공식 튜토리얼 - 틱택토 게임 만들기
- JavaScript 배열 메서드 - map, filter 등
