[React] Uncontrolled Components

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"));