React 폼 다루기 - Controlled Component 정리
React에서 input, textarea, checkbox, select 같은 폼 요소를 state로 완전히 제어하는 방법을 정리한다. Controlled Component 개념부터 다양한 입력 요소 처리, form의 onSubmit과 e.preventDefault()까지 다룬다.
Controlled Component란
input이 화면에 보여주는 값 자체를 state가 완전히 결정하도록 만드는 방식을 Controlled Component(제어 컴포넌트)라고 부른다.
// 이전 방식: state로 값을 읽기만 함 (value 연결 없음)
<input onChange={(e) => setText(e.target.value)} />
// Controlled Component 방식: value까지 state와 연결
<input value={text} onChange={(e) => setText(e.target.value)} />
input value 연결하기
import { useState } from "react";
function App() {
const [text, setText] = useState("");
return (
<div>
<input value={text} onChange={(e) => setText(e.target.value)} />
<p>입력한 값: {text}</p>
<button onClick={() => setText("")}>지우기</button>
</div>
);
}
value={text}가 있기 때문에, 지금 input에 보이는 값은 항상 text state와 정확히 같다. 그래서 "지우기" 버튼처럼 코드에서 setText("")를 호출하는 것만으로도 input 안의 글자를 화면에서 지울 수 있다.
value만 넣고 onChange를 안 넣으면 어떻게 될까? input에 아무리 타이핑을 해도 글자가 전혀 입력되지 않는다. state는 그대로인데 value가 계속 그 값으로 고정되기 때문이다. value와 onChange는 항상 짝을 이뤄야 한다.
다양한 입력 요소 다루기
| 요소 | 연결 방법 |
|---|---|
| input, textarea | value와 onChange |
| checkbox | checked와 onChange |
| select | value와 onChange (option을 자식으로 나열) |
import { useState } from "react";
function App() {
const [message, setMessage] = useState("");
const [agree, setAgree] = useState(false);
const [level, setLevel] = useState("beginner");
return (
<div>
<textarea
value={message}
onChange={(e) => setMessage(e.target.value)}
placeholder="자기소개를 입력하세요"
/>
<p>
<input
type="checkbox"
checked={agree}
onChange={(e) => setAgree(e.target.checked)}
/>
약관에 동의합니다 ({agree ? "동의함" : "동의 안 함"})
</p>
<select value={level} onChange={(e) => setLevel(e.target.value)}>
<option value="beginner">초급</option>
<option value="intermediate">중급</option>
<option value="advanced">고급</option>
</select>
<p>선택한 레벨: {level}</p>
</div>
);
}
checkbox는 value 대신 checked를 사용하고, e.target.value가 아니라 e.target.checked(true/false)로 값을 읽는다는 점이 다르다.
form과 onSubmit, e.preventDefault()
HTML의 form은 원래 제출(submit) 버튼을 누르면 페이지 전체가 새로고침된다. React에서는 이 기본 동작을 막고, 자바스크립트 코드로 직접 제출을 처리하는 경우가 많다.
import { useState } from "react";
function App() {
const [name, setName] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
alert(`${name}님, 제출이 완료되었습니다!`);
};
return (
<form onSubmit={handleSubmit}>
<input value={name} onChange={(e) => setName(e.target.value)} placeholder="이름" />
<button type="submit">제출</button>
</form>
);
}
e.preventDefault()를 안 쓰면 어떻게 될까? 제출 버튼을 누르는 순간 브라우저가 원래 하던 대로 페이지 전체를 새로고침해버린다. 그러면 name state를 포함해서 지금까지 화면에서 바뀐 모든 값이 초기화되고, handleSubmit 함수의 나머지 코드(alert 등)도 정상적으로 실행되지 않을 수 있다. e.preventDefault()는 "브라우저의 기본 제출 동작은 막고, 대신 내가 작성한 코드로 처리하겠다"는 뜻이다.
실습 정리
실습 1) input을 value + onChange로 완전히 제어하기 — text state를 만들고 input의 value, onChange를 모두 연결한 뒤, "지우기" 버튼을 만들어 즉시 값이 비워지는지 확인한다.
실습 2) checkbox 다뤄보기 — agree boolean state를 만들고, checkbox의 checked와 onChange를 연결해 "동의함" / "동의 안 함" 문구가 함께 바뀌도록 만든다.
실습 3) 회원가입 폼 만들기 — 이름과 이메일 input을 각각 state와 연결하고, form+onSubmit으로 제출 시 e.preventDefault() 후 입력값을 alert로 보여준다.
마무리
- Controlled Component의 핵심은
value(또는checked)와onChange를 항상 짝지어 쓰는 것이다. 하나만 쓰면 입력이 막히거나 경고가 뜬다. - checkbox는
value/e.target.value가 아니라checked/e.target.checked를 쓴다는 점이 다른 입력 요소와 구분되는 부분이다. form의 제출 이벤트를 다룰 땐e.preventDefault()로 브라우저의 기본 새로고침 동작을 막는 걸 잊지 말자.
'FullStack FrontEnd' 카테고리의 다른 글
| React Todo 앱 - 컴포넌트 분리하기 (0) | 2026.09.17 |
|---|---|
| React Todo 앱 설계하기 - 컴포넌트 트리와 상태 위치 결정 (0) | 2026.09.17 |
| React useEffect 기초 정리 - 컴포넌트 생명주기, 의존성 배열 (0) | 2026.09.17 |
| React 리스트 렌더링 정리 - map()과 key (0) | 2026.09.16 |
| React 조건부 렌더링 정리 - 삼항연산자, && 연산자 (0) | 2026.09.16 |