Uncontrolled Components
폼을 구현할 때에는 웬만하면 제어되는 컴포넌트를 사용하시기를 권합니다.
제어되는 컴포넌트를 사용하면, 폼 데이터가 React 에 의해 적절히 제어될 수 있기 때문입니다.
반면 제어되지 않는 컴포넌트를 사용하면, 폼 데이터는 DOM 의 자체 기능에 의해 제어됩니다.
제어되지 않는 컴포넌트를 만들 때에는 상태 업데이트를 위해 이벤트 핸들러를 작성할 필요가 없습니다.
대신 ref 를 사용해서 폼 데이터를 DOM 으로부터 가져올 수 있습니다.
예를 들어, 아래 코드는 제어되지 않는 컴포넌트를 통해 이름을 입력받습니다
class NameForm extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(event) {
alert("A name was submitted: " + this.input.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" ref={input => (this.input = input)} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
제어되지 않는 컴포넌트는 진리의 원천을 DOM 에 두기 때문에,
React 를 사용한 코드와 사용하지 않은 코드를 통합하는 작업을 좀 더 쉽게 만들어줄 수 있습니다.
그리고 코드의 양이 상대적으로 적습니다. 좀 지저분하지만 빠른 해결책을 원한다면 제어되지 않는 컴포넌트를 사용하세요.
그렇지 않다면, 제어되는 컴포넌트를 사용하세요.
아직 어떤 상황에서 무엇을 써야하는지 명확히 감이 오지 않는다면, 제어되는 input 과 제어되지 않는 input 에 대한 글이 도움이 될 수 있습니다.
기본값 지정하기
React 의 렌더링 라이프사이클에서는, 폼 엘리먼트에 지정된 value 어트리뷰트가 DOM 의 값을 덮어쓸 것입니다.
반면 제어되지 않는 컴포넌트를 사용할 때, DOM 의 상태변화는 제어되지 않는 상태로 두면서도 초기값을 지정해주어야 하는 경우가 있습니다.
이런 경우를 위해, defaultValue 어트리뷰트를 value 대신 사용할 수 있습니다.
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input
defaultValue="Bob"
type="text"
ref={(input) => this.input = input} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
비슷하게 <input type="checkbox">
와 <input type="radio">
엘리먼트는 defaultChecked 어트리뷰트를,
<select>
와 <textarea>
는 defaultValue 어트리뷰트를 지원합니다.
The file input Tag
HTML 에서, <input type="file">
태그는 서버에 업로드하거나 처리가 필요한 하나 이상의 파일을
기기 저장소에서 선택하는 데 사용되며, 이는 File API 를 통해 JavaScript 로 구현됩니다.
<input type="file" />
React 에서 <input type="file" />
는 언제나 제어되지 않는 컴포넌트인데,
왜냐하면 이 엘리먼트의 값은 오로지 사용자에 의해서만 지정될 수 있기 때문입니다.
(즉, 프로그래밍을 통해서 지정하는 것이 불가능)
입력받은 파일과 상호작용하기 위해서는 File API 를 사용해야만 합니다.
아래 예제는 submit 이벤트 핸들러 내에서 파일에 접근하기 위해 DOM node 를 가리키는 ref 를 생성하는 방법을 보여줍니다:
class FileInput extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(event) {
event.preventDefault();
alert(`Selected file - ${this.fileInput.files[0].name}`);
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Upload file:
<input
type="file"
ref={input => {
this.fileInput = input;
}}
/>
</label>
<br />
<button type="submit">Submit</button>
</form>
);
}
}
ReactDOM.render(<FileInput />, document.getElementById("root"));