Form Control

songsong·2020년 4월 22일
0

React

목록 보기
9/11
post-thumbnail

📖 Form Control

1. HTML Form Control

👉 HTML 폼 컨트롤 요소(<input />, <textarea>, <select> 등) 는 사용자의 입력 콘텐츠를 자체적으로 관리한다. JavaScript를 사용해 각 컨트롤의 value 값을 확인하면 사용자가 입력한 콘텐츠에 접근할 수 있다.

Exmple

const inputEmail = document.querySelector('#email')

// GET: HTML 폼 컨트롤 속성 값 읽기
console.log(inputEmail.value)

// SET: HTML 폼 컨트롤 속성 값 쓰기
inputEmail.value = 'songsong2920@gmail.com'

2. React Form Control

👉 React는 컴포넌트 상태 정보를 state 속성으로 관리하며 setState() 메서드를 사용해 상태를 업데이트(교체) 한다.

Exmple

// React Component
class BaseInput extends Component {
  // 컴포넌트 상태
  state = {
    content: ''
  };
  // 컴포넌트 메서드(이벤트 리스너)
  handleInput = (e) => {
    // 컴포넌트 상태(업데이트)
    this.setState({
      content: e.target.value
    });
  }
  // 컴포넌트 렌더 라이프 사이클 훅
  render() {
    return (
      <label>
        { this.props.label }
        <input
          type={this.props.type}
          value={this.state.content}
          onChange={e => this.handleInput(e)} />
      </label>
    );
  }
}

// React Element
const baseEmailInput = <BaseInput type="email" label="이메일" />

3. Controlled Component

👉 폼을 렌더링 하는 React 컴포넌트는 폼에서 발생되는 사용자의 입력 값을 컨트롤 한다. 이러한 방식으로 React에 의해 값이 컨트롤 되는 입력 폼 요소는 컨트롤 컴포넌트(Controlled Component) 이다.

3-1. <input> Control

👉 HTML From (<input> 포함)을 React에 의해 컨트롤 되는 컴포넌트로 변경할 수 있다.

Exmple (HTML Form)

<form onsubmit="onSubmitHandler">
  <label>
    @이메일: <input type="email" name="email" />
  </label>
  <button>전송</button>
</form>

Exmple (React Controlled Component)

class EmailForm extends Component {
  state = {
    email: ''
  };
  handleInput = (e) => {
    this.setState({
      email: e.target.value
    });
  }
  handleSubmit = (e) => {
    e.preventDefault();
    console.log(`입력하신 이메일 ${this.state.email}이 성공.`);
  }
  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          @이메일 :
          <input
            type="email"
            name="email"
            value={this.state.email}
            onChange={e => this.handleInput(e)} />
        </label>
        <button>전송</button>
      </form>
    )
  }

👉컨트롤 컴포넌트로 사용하면 모든 state의 업데이트는 연관된 이벤트 리스너(컴포넌트 메서드) 의해 처리된다. 컨트롤 컴포넌트를 통해 사용자의 입력 내용을 업데이트 하거나 유효성 검사하는 것이 가능하다. 입력 내용의 앞/뒤에 공백을 제거하고 싶다면 리스너 코드를 아래와 같이 수정한다.

Exmple

handleInput = (e) => {
  this.setState({
    email: e.target.value.trim();
  });
}

3-2. Multi <input> Handling

👉 하나 이상의 <input />을 하나의 리스너로 컨트롤 할 수 있다. 여러 개의 컨트롤을 제어하기 위해서는 name 속성을 설정해야 한다.

Exmple

class MultiControlInputs extends Component {
  state = {
    // 사용자 등록 정보 객체 (이메일, 패스워드)
    register: {
      email: '',
      password: ''
    };
  }
  // 멀티 <input /> 핸들링 핸들러
  handleChange = (e) => {
    // 이벤트 타겟 객체로부터 name, value 속성 구조 분해 할당
    const {name, value} = e.target;
    // Object.assign() 메서드를 사용해 객체 합성
    // register 객체 = 기존 register 객체에 사용자가 입력한 객체 합성
    const register = Object.assign({}, this.state.register, { [name]: value });
    // register 상태 업데이트
    this.setState({ register });
  }
  render() {
    const {register} = this.state;
    return (
      // Fragment
      <from>
        <input
          type="email"
          name="email"
          aria-label="계정 이메일"
          value={register.email}
          onChange={this.handleChange} />
        <input
          type="password"
          name="password"
          aria-label="계정 패스워드"
          value={register.password}
          onChange={this.handleChange} />
      </form>
    )
  }
}

3-3. <textarea> Control

👉 HTML <textarea> 요소는 사용자가 입력한 내용을 자식 텍스트 콘텐츠로 받는다.

Exmple(HTML Textarea)

<textarea> 내용을 입력.</textarea>

👉React는 value 속성을 대신 사용한다. 즉, 한 줄 입력을 사용하는 폼 컨트롤과 비슷하게 작성한다.

Exmple(React Textarea)

<textarea
  value={this.state.value}
  onChange={this.handleChange}
/>

3-3. <select> Control

👉 HTML <select> 요소는 드롭 다운 메뉴를 화면에 렌더링 한다.

Exmple (HTML Select)

<select>
  <option value="react">React</option>
  <option value="redux">Redux</option>
  <option selected value="reactRouter">React Router</option>
</select>

👉 HTML 드롭 다운 메뉴는 초기 활성화 값을 selected 속성을 사용해 처리하지만, React는 value 속성을 대신 사용한다.

Exmple (React Select)

<select
  value={this.state.value}
  onChange={this.handleChange}
>
  <option value="react">React</option>
  <option value="redux">Redux</option>
  <option value="reactRouter">React Router</option>
</select>

3-4. Multiple<select> Meun

👉 React 컨트롤 컴포넌트 구성된 <select> 요소는 사용자에 의해 복수의 아이템을 선택 받을 경우 두 가지가 요구 된다.

  1. multiple 속성 값이 true
  2. value 값은 Array

Exmple

<select multiple={true} value={this.state.value} onChange={this.handleChange}>

👉 value 값을 배열로 업데이트 받아야 하기 때문에 초기 값을 배열로 설정한 후, 핸들러 내부에서는 사용자의 멀티 선택을 배열 데이터로 만드는 공정을 거쳐 새로운 배열을 할당하여 업데이트 한다.
Exmple

state = {
  value: []
};
handleChange(e) {
  // select > option 요소 수집 후 배열 데이터로 변경
  const options = Array.from(e.target.children);
  // 사용자가 선택한 option 필터링
  const selectedOptions = options.filter(option => option.selected);
  // 필터링 된 option.value 값을 아이템으로 하는 새로운 배열 반환
  const selectedOptionsValue = selectedOptions.map(option => option.value);
  // 상태 업데이트
  this.setState({value: selectedOptionsValue});
}

4. Uncontrolled Component

👉 컨트롤 할 수 없는 컴포넌트는 form 요소가 React 외부에서 작동하는 것처럼 작동한다. 사용자가 form 필드(input box, dropdown 등)에 데이터를 입력하면 업데이트 된 정보가 React에서 별도 처리할 필요 없이 요소에 된다. 그러나, 이는 특정 필드가 특정 값을 갖도록 강제할 수 없다는 의미이다. 특별한 경우를 제외하고는 컨트롤 컴포넌트를 사용하는 것이 좋다.

4-1. File input 요소

👉 HTML에서 <input type="file" /> 요소는 사용자가 하나 이상의 파일을 자신의 로컬 컴퓨터에서 서버로 업로드 한다.

Exmple

<input type="file" />

👉 이 컴포넌트는 프로그래밍적으로 값을 설정 할 수 없고, 사용자만이 값을 설정할 수 있기 때문에 컨트롤 할 수 없는 컴포넌트(Uncontrolled Component) 이다. 컨트롤 할 수 없는 컴포넌트의 경우 DOM 자체에서 폼 데이터를 다루게 된다. (File API 사용) 모든 state 업데이트에 대한 이벤트 핸들러를 작성하는 대신 제어할 수 없는 컴포넌트를 만들려면 ref 속성을 사용해 DOM에서 폼 값을 가져올 수 있다.

5. 객체 참조(Ref)

👉 ref 속성은 render() 메서드에 생성된 DOM 노드나 React 요소에 접근하는 방법이다. 핸들러에서 파일에 접근하기 위해서 DOM 노드의 Ref(참조)를 만드는 방법.

📌 ref 속성은 실제 DOM 노드 또는 React 요소에 접근해 컨트롤 하는 방법으로 React.createRef() 메서드를 사용해 DOM 요소를 참조해야 한다.

Exmple

class FileInput extends Component {

  constructor(props) {
    super(props);
    // Ref를 사용해 DOM 요소 참조
    this.fileInput = React.createRef();
  }

  handleSubmit = (event) => {
    event.preventDefault();
    console.log(`선택된 파일: ${this.fileInput.current.files[0].name}`)
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          업로드:
          <input type="file" ref={this.fileInput} />
        </label>
        <br />
        <button type="submit">전송</button>
      </form>
    );
  }

}

5-1. 참조(Ref) 생성

👉 참조(Ref)는 React.createRef()를 통해 생성하고 ref 속성을 통해 DOM 노드 또는 React 요소에 참조 설정한다. 일반적으로 컴포넌트의 인스턴스가 생성(construct)될 때 참조를 인스턴스의 속성으로 추가한다.

Exmple

class RefExample extends Component {
  construtor(props) {
    super(props);
    // React.createRef()를 통해 Ref 생성 후,
    // 컴포넌트 인스턴스 속성에 참조
    this.refEl = createRef();
  }
  render() {
    return (
      <div className="ref-ex">
        {/* ref 속성 값으로 인스턴스 속성을 연결하여 DOM 요소 참조 */}
        <span ref={this.refEl}>Ref 요소 참조</span>
      </div>
    )
  }
}

5-2. 참조(Ref) 접근

👉 render() 메서드 안에서 ref 속성이 설정된 요소 참조는 ref.current 속성을 통해 접근할 수 있다.

📌 함수형 컴포넌트는 인스턴스가 없기 때문에 함수형 컴포넌트에 ref 사용하면 오류가 출력된다.

(Warning: Function components cannot be given refs. Attempts to access this ref will fail.)

Exmple

accessRef = () => {
  const span = this.refEl.current
  span.style.fontSize = '62px'
}

👉 React v16.8 부터는 useRef() 훅(Hook)을 사용해 함수형 컴포넌트에서도 ref 속성을 사용할 수 있다.

✍ Exmple

import React, {useRef} from 'react';

const FunctionalComponent = (props) => {
  const domElRef = useRef(null);
  return (
    <div ref={domElRef}> ... </div>
  );
}

0개의 댓글