[React][공식문서] 폼

Gyuwon Lee·2022년 6월 22일
1

React 공식 튜토리얼을 바탕으로, 필요한 개념을 보충하여 학습한 기록입니다.

1. 🛁 폼이란?

HTML의 에 대해 아직 익숙하지 않다면 MDN의 HTML 폼 가이드 를 얼른 훑어보는 것을 추천한다. 상세하고 쉽게 정리되어 있다. 다만 번역이 덜 되어 있다...

HTML 폼이란 사용자와 웹사이트 또는 어플리케이션이 서로 상호 작용하기 위한 요소로, 대부분 사용자가 웹사이트에 데이터를 전송하는 것을 가능케 한다. 텍스트 필드나 체크박스 또는 셀렉박스, 버튼 등이 전부 폼 위젯에 해당한다.

MDN 문서에 따르면, 모든 HTML 폼은 <form> 요소로 다음과 같이 시작된다:

<form action="/my-handling-form-page" method="post">
</form>

위 코드가 폼의 공식적인 형태이다. <form> 요소에 사용될 수 있는 속성은 선택적이지만, action 속성과 method 속성은 필수적으로 설정해야 한다.

  • action 속성은 데이터를 보낼 URL을 지정한다.
  • method 속성은 어떤 HTTP 방식을 사용할 것인지 지정한다.(GET 이나 POST)

기본적인 폼 예제

<form action="/my-handling-form-page" method="post">
    <div>
        <label for="name">Name:</label>
        <input type="text" id="name" name="user_name" />
    </div>
    <div>
        <label for="mail">E-mail:</label>
        <input type="email" id="mail" name="user_email" />
    </div>
    <div>
        <label for="msg">Message:</label>
        <textarea id="msg" name="user_message"></textarea>
    </div>

    <div class="button">
        <button type="submit">Send your message</button>
    </div>
</form>
  • label : 폼의 양식에 이름 붙이는 태그
    • for : label 의 주요 속성으로, labelfor 의 값양식의 id 의 값이 같으면 연결된다.
    • input 등 양식을 label 로 감싸면, idfor 가 없이도 같은 결과를 얻을 수 있다.
  • button : 폼에 입력된 사용자 데이터를 서버에 보낼수 있도록 추가하는 요소로, <button type="submit"> 으로 지정한다.
    • button 요소는 submit , reset , button 의 3개 종류가 있다.
    • submit 버튼을 클릭하면 폼 데이터를 <form> 요소의 action 속성에 정의된 웹페이지로 전송한다.

<input type='submit'> 요소를 사용해서도 버튼 요소를 만들 수 있다. 이 때 <button> 요소와 가장 큰 차이점은, <input> 요소로 만들어진 버튼은 오직 일반 텍스트만 보내는 반면 <button> 요소는 전체 HTML 콘텐츠를 보낸다는 점이다.


2. 제어 컴포넌트

<form>
  <label>
    Name:
    <input type="text" name="name" />
  </label>
  <input type="submit" value="Submit" />
</form>

이 폼은 사용자가 폼을 제출하면 새로운 페이지로 이동하는 기본 HTML 폼 동작을 수행한다.

리액트에서 이와 동일한 동작을 원한다면 위 코드를 그대로 사용하면 되지만, 대부분의 경우 자바스크립트 함수로 폼의 제출을 처리하고 사용자가 폼에 입력한 데이터에 접근하도록 하는 것이 편리하다.

이를 위한 표준 방식은 제어 컴포넌트 (controlled components) 라고 불리는 기술을 이용하는 것이다.

제어 컴포넌트란, 리액트에 의해 값이 제어되는 입력 폼 엘리먼트를 말한다. 여기서는 정확히 값이 state에 저장되고 setState() 에 의해서만 변경될 수 있는 엘리먼트를 말한다.

비제어 컴포넌트의 경우 기존처럼 DOM객체에서 데이터를 핸들링하는 반면, 제어 컴포넌트의 경우 리액트 컴포넌트(리액트)에서 데이터를 핸들링한다. 리액트 컴포넌트 자체의 state를 갱신하는 방식으로 동작하기 때문에 폼의 데이터가 항상 최신상태를 유지한다.

다만 그로 인해서 계속 리렌더링이 되어야 하고 (리액트 컴포넌트 state를 매번 변경하므로), 매 사용자 입력마다 이벤트가 발생할 수 있다. 참고


📌 valueonChange

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: '홍길동'};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

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

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input type="text" value={this.state.value} onChange={this.handleChange} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}
  • input 요소의 value{this.state.value} 로 지정했다.
    • this.state.value 는 맨 처음 "홍길동" 으로 초기화되어있다.
  • 사용자가 입력을 시작해 값이 변경되면, onChange 에 따른 이벤트 핸들러 this.handleChange 가 호출된다.
    • handleChange 는 state의 valueevent.target.value 로 변경한다.
    • 여기서 event.target 은 이벤트가 발생한 DOM 객체를 의미한다. 여기서는 input 요소가 된다. 따라서 event.target.valueinput 요소의 값을 의미한다.
  • 폼에서onChange 에 따른 이벤트 핸들러 없이 value 속성만 사용하게 되면, 사용자의 입력이 불가능하다. 브라우저는 아래와 같은 에러 메세지를 띄울 것이다:

You provided a value prop to a form field without an onChange handler. This will render a read-only field. If the field should be mutable use defaultValue. Otherwise, set either onChange or readOnly

  • onChange 핸들러 없이 value 속성만 사용했을 경우 리액트는 해당 요소를 읽기 전용 필드로 렌더링해버린다. 우리가 일반적으로 HTML에서 수정 가능한 초기값 을 설정하기 위해 value 를 사용한 것과는 다르다.
    • HTML에서의 value 기능을 사용하려면 defalueValue 속성을 사용하라고 한다.
  • 위 코드는 onChange 핸들러를 두어 사용자의 입력값으로 this.state.value 를 업데이트하고 있다. 이렇게 업데이트된 value 는 다시 input 요소의 value 속성의 값인 this.state.value 에 반영되어, 사용자가 입력할 때 보여지는 값이 업데이트된다.

즉 제어 컴포넌트에서, input 의 값은 항상 state에 의해 결정된다. 코드를 조금 더 작성해야 한다는 의미이지만, 다른 UI 엘리먼트에 input의 값을 전달하거나 다른 이벤트 핸들러에서 값을 재설정할 수 있다.


📌 select 태그

class FlavorForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: 'coconut'};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('Your favorite flavor is: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Pick your favorite flavor:
          <select value={this.state.value} onChange={this.handleChange}>
            <option value="grapefruit">Grapefruit</option>
            <option value="lime">Lime</option>
            <option value="coconut">Coconut</option>
            <option value="mango">Mango</option>
          </select>
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}
  • HTML 에서 select 요소는 선택가능한 드롭다운 목록을 만드는데, 이때 자식 요소인 option 요소에 selected 어트리뷰트를 사용해서 초기값을 지정할 수 있다.
<select>
  <option value="grapefruit">Grapefruit</option>
  <option value="lime">Lime</option>
  <option selected value="coconut">Coconut</option>
  <option value="mango">Mango</option>
</select>
  • 그러나 리액트에서는 selected 어트리뷰트를 사용하는 대신 최상단 select 태그에 value 어트리뷰트를 사용한다. 한 곳에서 업데이트만 하면 되기 때문에 제어 컴포넌트에서 사용하기에 더 용이하다.

제어 컴포넌트의 이점?

profile
하루가 모여 역사가 된다

0개의 댓글