🔠 Forms
HTML의 폼 element는 내부 상태를 가지기 때문에 React의 DOM element 와 조금 다르게 작동합니다. 아래 예제는 HTML에서 한개의 이름을 입력하는 폼 입니다.
<form>
<label>
Name:
<input type="text" name="name" />
</label>
<input type="submit". value="submit" />
</form>
이 폼은 사용자가 폼을 제출하면 새로운 페이지로 이동하는 HTML의 기본 폼 동작을 가지고 있습니다. 만약 React에서 이 동작을 원하면 이대로 사용하면 됩니다. 하지만 대부분의 경우, JS의 함수가 폼의 제출을 조작하고 사용자가 폼에 입력하는 데이터에 접근하도록 하는 것이 더 편리합니다. 이런 표준 방식을 “제어 컴포넌트 ( controlled components
)” 라고 부릅니다.
🎛️ 제어 컴포넌트
HTML에서 <input>
, <textarea>
, <select>
같은 폼 element 는 보통 자신의 state를 유지하고 사용자 입력 값과 같도록 업데이트합니다. React에서는 변경할 수 있는 state가 컴포넌트의 state로 있다가 오직 setState()
로 변경합니다.
React state를 “신뢰 가능한 단일 출처( single source of truth
)”로 만들어서 두 가지를 결합할 수 있습니다. 그러면 폼을 렌더링 하는 React 컴포넌트는 사용자 입력 다음 폼을 조작할 수 있습니다. 입력 폼 element의 값은 React의 “제어 컴포넌트” 라고 불리는 방법으로 조작됩니다. 제어 컴포넌트를 이용해서 이전 예제에서 이름이 제출 될 때 로그에 찍는 예제를 만들겠습니다.
value
속성은 폼 element에 설정 되므로 value
는 항상 this.state.value
를 표시하고 React의 “신뢰 가능한 단일 출처” 가 됩니다. handleChange
가 모든 키 입력 마다 실행되기 때문에 React state를 업데이트 하고 표시 되는 값도 업데이트가 됩니다.
제어 컴포넌트에서, 입력 값은 항상 React state에 의해 결정됩니다. 이 뜻은 코드를 조금 더 입력해야 하지만 value
을 다른 UI element에게 전달할 수 있고, 다른 이벤트 핸들러로 재설정을 할 수 있습니다.
textarea 태그
HTML에서 <textarea>
element는 자식으로 텍스트를 정의합니다.
<textarea>
Hello there, this is some text in a text area.
</textarea>
React의 <textarea>
는 자식 대신 value
속성을 사용합니다. <textarea>
를 이용한 폼은 한줄 입력 폼과 비슷하게 작성할 수 있습니다.
여기서 this.state.value
를 생성자에서 초기 설정해서 <textarea>
가 Please write an …
로 시작했습니다.
select 태그
HTML에서 <select>
는 드롭-다운 (drop-down) 리스트를 만듭니다. 아래는 과일의 드롭 다운 리스트 입니다.
<select>
<option value="grapefruit">Grapefruit</option>
<option value="Lime">Lime</option>
<option selected value="coconut">Coconut</option>
<option value="Mango">Mango</option>
</select>
selected
속성 때문에 “Coconut” 이 기본 선택 되어있습니다. React에서는 selected
속성 대신에 select
태그의 value
속성을 사용합니다. 이것은 한 가지만 업데이트하면 되기 때문에 제어 컴포넌트에게 편리성을 제공합니다.
전체적으로 <input type=“text”>
, <textarea>
, <select>
모두 value
속성으로 제어할 수 있는 점이 비슷합니다. <select>
의 multiple
속성에 true
를 주면 value
속성에 배열을 전달할 수 있습니다.
file input 태그
HTML에서 <input type=“file”>
은 사용자가 한 개 또는 그 이상의 파일을 서버에 올리거나 File API
를 통해 JS로 조작하게 해줍니다.
<input type="file" />
이 값은 읽기 전용 이기 때문에 React에서 “비제어 컴포넌트 ( uncontrolled components
)” 라고 합니다.
여러 개의 입력 조작
여러 개의 input
element를 조작해야할 때 각 element에 name
속성을 추가하고 핸들러 함수에서 event.target.name
으로 선택할 수 있습니다.
입력 name에 해당하는 state key를 업데이트 하는 ES6 계산된 속성명 ( computed property name
) 문법을 참고하세요.
this.setState({
[name]: value
});
이것은 아래의 ES5 코드와 같습니다.
var partialState = {};
partialState[name] = value;
this.setState(partialState);
또한 setState()
가 부분적인 state를 현재 state로 자동 병합하기 때문에 바뀐 부분만 호출만 하면 됩니다.
Null 입력 값 제어
제어 컴포넌트에 value
prop을 지정하면 의도하지 않는 한 사용자가 변경할 수 없습니다. 만약 value
를 명시하지만 수정이 가능하면 뜻하지 않게 value
를 undefined
또는 null
로 설정되었을 수 있습니다. 아래 코드가 그것을 보여줍니다. (처음엔 입력을 못하지만 1초 뒤에 수정 가능하게 바뀝니다.)
ReactDOM.render(<input value="hi" />, document.getElementById('root'));setTimeout(function() {
ReactDOM.render(<input value={null} />, document.getElementById('root'));
}, 1000);
💡 완전한 해결책
유효성 검사, 방문한 필드 추적, 폼 제출 조작 등 완벽한 해결책을 찾고 있다면 Formik 은 대중적인 선택 중 하나 입니다. 하지만 이것은 제어 컴포넌트와 상태 관리에 기초하기 때문에 배우는 것을 쉽게 생각하면 안됩니다.
📚 정리 및 참고 자료
- React에서 JS의 함수를 이용해서 폼을 제어하는 방법을 “제어 컴포넌트" 라고 합니다.
- React는 입력 값과 React의 state를 연결해서 입력 값이 바뀔 때마다
setState()
로 업데이트 합니다. - 하나의 폼에서 여러개의 값을 제어할 때는
event.target.name
으로 선택할 수 있습니다. - 제어 컴포넌트에서
value
prop 을 지정하면 사용자가input
의value
를 변경할 수 없습니다. 하지만 의도치 않게 prop의value
가undefined
또는null
로 설정되면 수정이 가능합니다.