1. 리액트에서 폼이 중요한 이유
리액트를 사용하다 보면 사용자 입력을 다뤄야 하는 경우가 매우 많습니다.
회원가입, 로그인, 검색창, 댓글 입력 등 — **폼(Form)**은 거의 모든 웹 애플리케이션의 기본입니다.
일반 HTML에서는 <input>의 값을 브라우저가 직접 관리하지만,
리액트에서는 컴포넌트가 입력값을 직접 관리합니다.
이 방식을 **Controlled Component (제어 컴포넌트)**라고 부릅니다.
2. Controlled Component란?
Controlled Component는 말 그대로 **컴포넌트가 입력값을 제어(control)**하는 구조입니다.
즉, 입력 필드의 값이 컴포넌트의 state와 연결되어,
사용자의 입력이 있을 때마다 state를 업데이트합니다.
아래 예제를 보세요.
import React, { useState } from 'react';
function NameForm() {
const [name, setName] = useState('');
const handleChange = (e) => {
setName(e.target.value);
};
const handleSubmit = (e) => {
e.preventDefault();
alert(`입력한 이름: ${name}`);
};
return (
<form onSubmit={handleSubmit}>
<label>
이름:
<input type="text" value={name} onChange={handleChange} />
</label>
<button type="submit">제출</button>
</form>
);
}
export default NameForm;
이 코드의 핵심은 value={name}과 onChange={handleChange}입니다.
이 두 줄 덕분에 입력창의 값이 항상 state와 일치하게 됩니다.
3. 왜 Controlled Component를 사용하는가?
그 이유는 간단합니다 — 리액트의 단방향 데이터 흐름 때문입니다.
HTML에서는 입력 필드가 스스로 값을 관리하지만,
리액트는 모든 데이터를 컴포넌트 상태(State)로 통합해 관리합니다.
따라서 입력값을 state에 저장하면,
- 유효성 검사(Validation)를 쉽게 수행할 수 있고
- 입력값을 다른 컴포넌트나 API 요청에 쉽게 연결할 수 있으며
- 특정 상황에서 입력을 비활성화하거나 초기화하기도 간단합니다.
4. 여러 개의 입력 필드 관리하기
입력 필드가 여러 개라면 name 속성을 활용하면 효율적으로 관리할 수 있습니다.
function SignupForm() {
const [form, setForm] = useState({
username: '',
email: '',
});
const handleChange = (e) => {
const { name, value } = e.target;
setForm({ ...form, [name]: value });
};
const handleSubmit = (e) => {
e.preventDefault();
console.log(form);
};
return (
<form onSubmit={handleSubmit}>
<input
name="username"
placeholder="이름"
value={form.username}
onChange={handleChange}
/>
<input
name="email"
placeholder="이메일"
value={form.email}
onChange={handleChange}
/>
<button type="submit">등록</button>
</form>
);
}
여기서 setForm({ ...form, [name]: value })는
기존 객체를 복사하면서 입력된 필드의 값만 업데이트합니다.
이렇게 하면 여러 입력값을 한 state에서 깔끔하게 관리할 수 있습니다.
5. 체크박스(Checkbox) 제어하기
체크박스도 Controlled Component로 다룹니다.
function CheckboxExample() {
const [checked, setChecked] = useState(false);
return (
<label>
<input
type="checkbox"
checked={checked}
onChange={(e) => setChecked(e.target.checked)}
/>
이용약관에 동의합니다.
</label>
);
}
여기서 checked 속성은 단순히 value 대신 사용됩니다.
e.target.checked는 boolean 값을 반환하므로, 상태가 true/false로 전환됩니다.
6. 셀렉트 박스(Select) 제어하기
셀렉트 박스도 동일한 원리로 제어합니다.
function SelectExample() {
const [language, setLanguage] = useState('javascript');
return (
<form>
<label>
사용 언어:
<select value={language} onChange={(e) => setLanguage(e.target.value)}>
<option value="javascript">JavaScript</option>
<option value="python">Python</option>
<option value="java">Java</option>
</select>
</label>
<p>선택한 언어: {language}</p>
</form>
);
}
select 태그의 value도 리액트가 제어하므로,
사용자가 선택할 때마다 state가 업데이트되고 자동으로 반영됩니다.
7. 비제어 컴포넌트(Uncontrolled Component)
가끔은 폼 데이터를 굳이 상태로 관리하지 않아도 될 때가 있습니다.
그럴 때는 **Uncontrolled Component (비제어 컴포넌트)**를 사용합니다.
이 방식에서는 ref를 이용해 DOM 요소에 직접 접근합니다.
import React, { useRef } from 'react';
function UncontrolledForm() {
const inputRef = useRef(null);
const handleSubmit = (e) => {
e.preventDefault();
alert(`입력한 값: ${inputRef.current.value}`);
};
return (
<form onSubmit={handleSubmit}>
<input ref={inputRef} placeholder="이름 입력" />
<button type="submit">확인</button>
</form>
);
}
비제어 컴포넌트는 간단하지만,
상태 변화에 따른 리렌더링이나 유효성 검사가 어려워
대부분의 경우 Controlled 방식이 더 적합합니다.
8. Controlled vs Uncontrolled 비교
구분 Controlled Component Uncontrolled Component
| 관리 주체 | React state | DOM 자체 |
| 장점 | 일관된 데이터 관리, 유효성 검사 용이 | 코드 간결, 빠른 구현 |
| 단점 | 코드 길어짐, 약간의 오버헤드 | 상태 추적 불가능, 유지보수 어려움 |
| 주로 사용되는 곳 | 로그인, 회원가입, 입력 검증 | 단순한 검색창, 임시 입력값 |
9. 마무리
이번 강의에서는 리액트에서 폼 데이터를 다루는 핵심 방법,
Controlled Component 개념과 다양한 입력 요소 제어 방식을 배웠습니다.
핵심 포인트를 정리하면 다음과 같습니다.
- 모든 입력값은 value와 onChange를 통해 state와 연결된다.
- 여러 입력을 관리할 때는 객체 상태와 [name] 문법을 활용한다.
- 체크박스 → checked, 셀렉트 박스 → value로 제어한다.
- useRef를 활용한 Uncontrolled 방식도 존재하지만 제한적이다.
다음 글에서는 리액트의 핵심 개념 중 하나인 **Hooks(useState, useEffect)**를 다뤄보겠습니다.
함수형 컴포넌트에서 상태와 생명주기를 관리하는 방법을 단계별로 살펴보겠습니다.
'frontend > react' 카테고리의 다른 글
| Next.js hydration error #418 원인과 해결 방법 정리 (0) | 2026.03.23 |
|---|---|
| [React] React.js 강좌 25. Context API로 전역 상태 관리하기 (0) | 2025.12.04 |
| [React] React.js 강좌 7. 조건부 렌더링 (Conditional Rendering) (0) | 2025.11.11 |
| [React] React.js 강좌 6. 리스트 렌더링과 Key 속성의 원리 (0) | 2025.11.11 |
| [React] React.js 강좌 5. 이벤트 처리와 Binding 이해 (0) | 2025.11.11 |