제어 컴포넌트 vs 비제어 컴포넌트

devAnderson·2022년 2월 3일
0

TIL

목록 보기
49/103

제어 컴포넌트

공식문서에 따르면 제어컴포넌트의 설명은 아래와 같다

변경 가능한 값을 상태로 관리하는데, 리엑트 컴포넌트는 폼에 입력되는 사용자값을 제어한다고 한다.
이 말만 봐서는 도대체 무슨소린가 싶을것이다. 아래의 예시를 보면

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

아하! 하고 위의 내용을 보면 이해가 된다.
클래스 컴포넌트로 써져있지만 함수 컴포넌트로 치면 useState을 통해 상태를 만든다.
일반적으로 input이라고 하는 요소의 노드 형태를 따지고 보면 아래와 같은 객체 형태로 되어있다.

// input 
{
   type,
   value,
   onchange,
}

원래대로라면 input에 무엇을 입력하면 자동으로 해당 객체의 value 프로퍼티의 값에 입력이 된다.
그렇지만 이 value 자체를 리엑트 컴포넌트의 상태로 제어함으로써, single source of truth를 지키게 되고
다른 컴포넌트에 prop으로 해당 값을 손쉽게 전달할 수 있도록 만든다는 것이다

비제어 컴포넌트

그렇다면 비제어 컴포넌트는 이와 반대되는 개념일 것이라는 확신을 할 수 있다.
공식문서에 따르면 비제어 컴포넌트의 정의는 아래와 같다.

말 그대로, DOM 자체에서 폼 데이터를 다루는 방식을 뜻한다.
방금 전의 input에 비유하면 그냥 input의 노드에 저장되는 값을 사용하는 것과 같은 의미이다.

위와같은 작업을 위해 고전적인 document.querySelect와 같은 선택자 메서드를 이용하는 것도 가능하겠지만,
리엑트의 철학중에는 DOM에 직접적으로 접근하는 것을 최대한 자제하길 바라므로, 이를 위해 노드 객체를 담기 위한
"Ref" 를 사용하여 간접적으로 조회하고 변경하는 것을 요구한다.

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

위와 같이, input 자체에 ref를 걸어둔 후, 이 ref에 담겨있는 노드객체의 프로퍼티 값을 변경하는 방식으로 비제어 컴포넌트의 폼 제어를 완성시킨다.

그렇다면, 두 방식에 대해서 뭘 선택해야되는지에 대한 의문이 들 수밖에 없다.
(실제로 어제까지만 해도 계속 리랜더링을 안시키도록 비제어 방식으로 값을 만들다가 나중에 submit 단계에서만 컨트롤하면 되지 않을까 하는 고민을 하고 있었다)

controlled vs uncontrolled

공식문서에서 첨부한 링크를 타고 글을 읽어보면 두 방식은 자신만의 메리트가 있으므로 "반드시" controlled한 방법을 사용할 필요는 없다고 한다.

그도 그럴것이, 어차피 controlled한 방식 역시 node가 가지고 있는 프로퍼티를 그대로 상태로 업데이트하고 리랜더링을 시키고 있기 때문에 자원의 출처는 결국 node 객체가 가지고 있는 그것 자체이기 때문이다.

다만, react 내에서 controlled한 방식을 따르는 것은 UI적인 장점이 존재한다.

  1. 즉각적인 리 랜더링으로 인해 각 필드의 vailidation을 제공하는 데에 용이하다.
  2. 조건부로 상태에 따라 무언가 다른 UI를 보일 수 있다.
  3. 상태에 대해 특정 값만 들어가도록 강제할 수 있다

즉, 단순하게 필드 내에 값을 입력하고 그것을 전송하기 위한 용도면 비제어 방식은 완전하게 괜찮지만,
랜더링과 관련하여 UI적으로 입력되는 폼과 연동한 무언가를 보이고 싶다면 컨트롤되는 컴포넌트를 작성하는 편이 낫다.

그리고 일반적으로, UI가 관련이 안될 일이 전혀 없기 때문에 해당 방식이 관습적으로 사용되는 것이다.

profile
자라나라 프론트엔드 개발새싹!

0개의 댓글