대부분의 경우 폼을 구현하는데 제어 컴포넌트를 사용하는게 좋지만 제어 컴포넌트에서 폼 데이터는 React에서 다루어진다. 대안인 비제어 컴포넌트는 DOM자체에서 폼 데이터가 다루어진다.

비제어와 제어가 통합된 환경에서 사용한다.

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.input = React.createRef();
  }

  handleSubmit(event) {
    alert('A name was submitted: ' + this.input.current.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input type="text" ref={this.input} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

특정 상황에서 사용해야 하는 컴포넌트의 타입이 명확하지 않은 경우, https://goshacmd.com/controlled-vs-uncontrolled-inputs-react/ 이걸 읽어보

기본 값

React 폼 엘리먼트의 value 어트리뷰트는 DOM의 value를 대체한다. 비제어 컴포넌트를 사용하면 React의 초기값을 지정하지만, 그 이후의 업데이트는 제어하지 않는게 좋다. 이러한 경우에는 defaultValue 어트리뷰트를 사용하자. 컴포넌트가 마운트된 후에 defaultValue를 변경해도 DOM의 값이 변경되지는 않는다.

또한 checkbox, radio는 defaultChecked를 지원하고 select와 textarea는 defaultValue를 지원한다.


파일 입력 태그

파일 태그는 비제어 컴포넌트이기 때문에 ref를 걸어서 사용하자.

class FileInput extends React.Component {
  constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.fileInput = React.createRef();
  }
  handleSubmit(event) {
    event.preventDefault();
    alert(
      `Selected file - ${this.fileInput.current.files[0].name}`
    );
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Upload file:
          <input type="file" ref={this.fileInput} />
        </label>
        <br />
        <button type="submit">Submit</button>
      </form>
    );
  }
}

const root = ReactDOM.createRoot(
  document.getElementById('root')
);
root.render(<FileInput />);