상세 컨텐츠

본문 제목

controlled component vs uncontrolled component

React

by nata_developer 2020. 8. 10. 15:12

본문

1. WHY CONTROLLED COMPONENTS & UNCONTROLLED COMPONENTS ?

React는 내부의 상태(state)를 '신뢰 가능한 단일 소스(Single Source of Truth)'

 

관리하려는 설계 원칙을 가지고 있다.

 

자식 컴포넌트가 data가 필요할 경우, 해당 data는 가장 가까운

 

공통 부모 컴포넌트에게서만 props의 형태로 전달받아서 사용해야 한다.

 

대부분의 HTML 엘리먼트들(ex. <div> 등)은 엘리먼트가 내부적으로

 

어떤 데이터를 가지지 않기 때문에 문제될 것이 없다.

 

하지만 HTML 엘리멘트 중 자체적으로 특정 data를 가지는 엘리먼트들이 있다.

 

바로 <form> 태그의 엘리먼트들이다.(<input>, <textarea>, <select> 등)

 

이들은 user가 DOM에서 어떤 정보를 입력하거나 선택할 경우,

 

해당 정보를 HTML 엘리먼트가 직접 보관하게 되는데,

 

이는 위에서 언급한 리액트의 핵심 설계원리인 '신뢰 가능한 단일 소스' 원칙에 위배되는 상황이다.

 

따라서 이를 해결하기 위해서 React에서 Controlled 컴포넌트의 개념이 나온 것이다.

 

하지만 무조건 Controlled Component로만 만드는 것이 항상 정답이라는 의미는 아니다.

 

상황에 따라서는 uncontrolled component로도 충분한 경우도 있다.

 

2. Uncontrolled Component : 'PULL' the value

1.Uncontrolled Component는 전통적인 HTML form input과 유사하다.

 

2.React Component가 DOM이 관리하는 정보를 알기 위해서는

 

실제 DOM에 접근할 수 있는 방법이 필요한데, 그것이 바로 <input> 태그 내부에 부여된 ref이다

 

.ref prop에 넘겨진 콜백함수는 componentDidMount()

 

또는 componentDidUpdate() 직전에 호출된다.

 

3.따라서 componentDidMount()가 실행되는 시점에는

 

DOM에서 ref를 통해서 받아온 정보에 대한 참조를 저장할 수 있다.

 

4.그리고 최종적으로 handleSubmitClick 메소드가 버튼 클릭으로 실행될 때

 

해당 참조에 대한 정보를 컴포넌트 내부에 저장한 후 추가적인 작업을 할 수 있다.

 

5.실질적으로는 React Component가 HTML 엘리먼트에서 정보를 PULL하여 사용하는 방식이다.

 

6.컴포넌트 내부에서 실시간으로 user 정보를 관리하는 것이 아니기 때문에

 

실시간으로 작업을 처리할 때(ex. 입력이 완료되기 전까지 버튼을 숨기는 등의 행위)에는 부적합한 방식이다.

 

3. Controlled Component : 'PUSH' the value

1.Form element의 value를 component의 prop으로 설정하고

 

이를 활용하면 "Controlled Component"이다

 

2.Controlled Component는 현재 HTML 엘리먼트에 들어온 정보를

 

prop으로 state를 변경시키고, 변경된 state를 기반으로

 

HTML 엘리먼트의 value를 변경시키는 방식이다.

 

3.DOM의 정보를 컴포넌트 내부에 state로 저장하고 state를 기반으로

 

HTML 엘리먼트를 다시 re-rendering시키기 때문에

 

이 방식이 더 React스러운 방식이라고 할 수 있다.

 

4.user가 정보를 input 태그에 입력하면 onChange 메소드가 실행되면서

 

Component 컴포넌트의 내부 state의 값을 유저가 입력한 값으로 변경시킨다.

 

5.state가 update되면서 컴포넌트가 re-rendering되는데,

 

re-rendering 시에 input 태그의 value에 현재 변경된 state를 부여한다.

 

6.user 입력을 state로 저장 => re-rendering => user 입력을 value로 주어 실시간으로 화면에 반영

 

7.이 방식을 통해 React Component에 내장된 state를 기반으로 작동하도록 HTML form 태그를 변경시켜,

 

this.state.name이라는 '신뢰 가능한 단일 소스'를 기반으로 컴포넌트가 작동되도록 변경하였다.

 

8.user 정보를 기반으로 state를 변경시킨 후, 다시 해당 state를 input 태그의 value로 설정하고 있기 때문에

 

uncontrolled component와 달리 데이터를 'PUSH'하는 방식이라 할 수 있다.

 

이 방식을 취하면 react가 내부적으로 관리하는 state와

 

유저가 입력하는 정보 간의 sync가 맞기 때문에

 

uncontrolled component에서는 불가능했던 실시간 작업 처리가 가능해진다.

 

실시간으로 field validation을 체크하거나,

 

조건에 따라 submit button을 disabling하는 등

 

실시간으로 user에게 정보를 일러줘야 할 때에 사용하기 좋다.

 

참고-https://soldonii.tistory.com/145

 

200207(금) : Uncontrolled vs. Controlled Component in React

React의 컴포넌트를 설명할 때 Uncontrolled Component와 Controlled Component라는 개념이 있다. 이 둘에 대해서 살펴보자. 1. 왜 uncontrolled와 controlled 컴포넌트에 대해 알아야 할까? React는 내부의 상태(..

soldonii.tistory.com

4.예제

App.js

import React from "react";
import SearchBar from "./SeachBar";
import ImageList from "./ImageList"
import unsplash from "../apis/unsplash"

class App extends React.Component {
  state = { images: [] };

  onSearchSubmit = async term => {
    const response = await unsplash.get('/search/photos', {
      params: { query: term }
    });

    this.setState({ images: response.data.results });
  };

  render() {
    return (
      <div className="ui container" style={{ marginTop: "10px" }}>
        <SearchBar onSubmit={this.onSearchSubmit} />
        <ImageList images={this.state.images} />
      </div>
    );
  }
}

export default App;

SearchBar 컴포넌트에 onSubmit이라는 props를 통해 onSearchSubmit이라는 메써드를 전달한다.

 

SearchBar에서 term 값을 넘겨 받은 App 컴포넌트로 콜백한다.

 

SearchBar.js

import React from "react";

class SearchBar extends React.Component {
  state = { term: "" };

  onFormSubmit = (event) => {
    event.preventDefault();

    this.props.onSubmit(this.state.term);
  };

  render() {
    return (
      <div className="ui segment">
        <form onSubmit={this.onFormSubmit} className="ui form">
          <div className="field">
            <label>Image Search</label>
            <input
              type="text"
              value={this.state.term}
              onChange={(e) => this.setState({ term: e.target.value })}
            />
          </div>
        </form>
      </div>
    );
  }
}

export default SearchBar;

 

'React' 카테고리의 다른 글

Blog App 1 Scaffold  (0) 2020.08.20
Redux  (0) 2020.08.11
class component vs functional component  (0) 2020.08.10
Props  (0) 2020.08.09
React  (0) 2020.08.09

관련글 더보기