목표
<form>
<label>
Name:
<input type="text" name="name" />
</label>
<input type="submit" value="Submit" />
</form>
- 이 폼은 사용자가 폼을 제출하면 새로운 페이지로 이동하는 기본 HTML 폼 동작을 수행합니다.
- React에서 동일한 동작을 원한다면 그대로 사용하면 됩니다.
- 그러나 대부분의 경우, JavaScript 함수로 폼의 제출을 처리하고 사용자가 폼에 입력한 데이터에 접근하도록 하는 것이 편리합니다.
- 이를 위한 표준 방식은 “제어 컴포넌트 (controlled components)“라고 불리는 기술을 이용하는 것입니다.
9-1. 제어 컴포넌트
- 리액트에서는 변경할 수 있는 state가 일반적으로 컴포넌트의 state 속성에 유지되며 setState()에 의해 업데이트된다.
- 리액트 컴포넌트는 폼에 발생하는 사용자 입력값을 제어하는데 이 때, 리엑트에 의해 값이 제어되는 입력 폼 엘리먼트를 제어 컴포넌트(controlled component)라고 한다.
- 다음 코드는 input, textarea, select 등 제어 컴포넌트를 이용해 state를 업데이트하는 내용이다.
export default function ControlledComponent() {
const [name, setName] = useState("");
const [essay, setEssay] = useState("");
const [flavor, setFlavor] = useState("");
function handleChange(event) {
setName(event.target.value);
}
function handleEssayChange(event) {
setEssay(event.target.value);
}
function handleFlavorChange(event) {
setFlavor(event.target.value);
}
function handleSubmit(event) {
alert(`name: ${name}, essay: ${essay}, flavor: ${flavor}`);
event.preventDefault();
}
return (
<form onSubmit={handleSubmit}>
<div>
<label>
Name:
<input name="name" type="text" value={name} onChange={handleChange} />
</label>
</div>
<div>
<label>
Essay:
<textarea name="essay" value={essay} onChange={handleChange} />
</label>
</div>
<div>
<label>
Pick your favorite flavor:
<select name="flavor" value={flavor} onChange={handleChange}>
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
</label>
</div>
<input type="submit" value="Submit" />
</form>
);
}
- 리액트는 제어 컴포넌트에 대해 다음과 같이 말한다.
- 제어 컴포넌트로 사용하면, input의 값은 항상 React state에 의해 결정됩니다.
- 코드를 조금 더 작성해야 한다는 의미이지만, 다른 UI 엘리먼트에 input의 값을 전달하거나 다른 이벤트 핸들러에서 값을 재설정할 수 있습니다.
9-1-1. 제어 컴포넌트가 뭘까?
- 한마디로 input, textarea, select 등의 value를 state로 관리할 수 있는 컴포넌트를 말한다.
9-2-1. 다중 입력 제어하기
- 여러 input 엘리먼트를 제어해야할 때, 각 엘리먼트에 name 어트리뷰트를 추가하고
event.target.name
값을 통해 핸들러가 어떤 작업을 할 지 선택할 수 있다.
function handleChange(event) {
setName(event.target.value);
}
function handleEssayChange(event) {
setEssay(event.target.value);
}
function handleFlavorChange(event) {
setFlavor(event.target.value);
}
<input name="name" type="text" value={name} onChange={handleChange} />
<textarea name="essay" value={essay} onChange={handleChange} />
<select name="flavor" value={flavor} onChange={handleChange}>
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
- 코드 일부를 보면 input, textarea, select 엘리먼트에 있는 name에 값이 설정되어 있는데 event.target.name 통해 여러 개의 입력을 한 번에 제어 할 수 있다.
function handleChange(event) {
const name = event.target.name;
if (name === "name") {
setName(event.target.value);
}
if (name === "essay") {
setEssay(event.target.value);
}
if (name === "flavor") {
setFlavor(event.target.value);
}
}
9-2. 비제어 컴포넌트
- 리액트에서 다음과 같이 하는 것이 좋다고 말한다.
- 대부분 경우에 폼을 구현하는데 제어 컴포넌트를 사용하는 것이 좋습니다. 제어 컴포넌트에서 폼 데이터는 React 컴포넌트에서 다루어집니다.
- 대안인 비제어 컴포넌트는 DOM 자체에서 폼 데이터가 다루어집니다.
- 하지만, 비제어 컴포넌트(uncontrolled components)를 써야하는 경우가 존재한다.
export default function UncontrolledComponent() {
const fileInput = useRef(null);
function handleSubmit(event) {
event.preventDefault();
alert(`Selected file - ${fileInput.current.files[0].name}`);
}
return (
<form onSubmit={handleSubmit}>
<label>
Upload file:
<input type="file" ref={fileInput} />
</label>
<br />
<button type="submit">Submit</button>
</form>
);
}
- 리액트에서 type이
file
인 컴포넌트는 대표적인 비제어 컴포넌트인데 그 이유는 프로그래밍적으로 값을 설정 할 수 없고 사용자만이 값을 설정할 수 있기 때문이다.
- 비제어 컴포넌트는
ref
를 사용하여 DOM에서 폼 값을 가져올 수 있다.
9-2-1. 비제어 컴포넌트가 뭘까?
- 한마디로 폼 엘리먼트 자체의 내부 상태를 활용하는 컴포넌트를 말한다.
출처