controlled components vs uncontrolled components

euneun·2022년 2월 9일
0

React

목록 보기
4/5

서론

왜 리액트에서 인풋값을 다룰때에는 value 속성을 이용해서 내부의 state를 전달해주어야할까?

html의 기본 input 태그를 사용할 수 있지만,
보통 이런 기본 html 폼들은 제출했을때 새로고침을 시킨다.

근데 우린 이런걸 원하지 않고 제출을 직접 커스텀하여 핸들링하고
입력된 값을 직접 다루고 싶다..!

-> 이럴때 리액트의 controlled component를 사용한다!

또한 리액트에서는 controlled components를 사용하는것을 권장하고 있다.

그래서 controlled components란?

html의 기본 input, textarea, select 같은 태그는 자기 스스로 상태를 유지하고 사용자 입력을 기반으로 값을 업데이트한다.

근데 리액트에서는 변경가능한 상태가 보통 컴포넌트의 state에 달려있기 마련이다.

따라서 리액트 컴포넌트와 기본 html 인풋 태그를 잘 합치면
리액트 안의 statesingle source of truth가 되도록 할 수 있음!!

이런식으로 리액트에 의해 제어되는 인풋 폼 요소를 controlled components라고 함!

즉 리액트에서 value={state} 이렇게 value 속성을 기본 인풋 태그에 넣어주면
-> 보여지는 값(value)을 리액트가 제어할 수 있게되고
-> single source of truth가 된다. (원래 인풋태그의 기본 value와 리액트가 제어할 수 있는 상태값이 들어간 value가 하나의 source(근원지?)를 가지게됨)

이게 리액트가 지향하는 방법임!

근데 왜 controlled components를 지향하는걸까?

  • single source of truth를 지키기 위해??
    • 그니까 DOM이 폼데이터를 관리하면, 내가 그 데이터를 가져오기 위해서 리액트 코드를 사용하는데 이로써 원천이 두갈래로 나뉘어짐.
    • 근데 controlled components를 사용하면 데이터의 원천이 컴포넌트의 내부 state에 있으므로 single source of truth가 보장되기 때문에..?

그리고 여러개의 인풋을 다루고 싶다면
name 속성을 부여해서 e.target.name으로 관리할 수 있따!

또한, controlled components를 사용하게되면
데이터(state)와 UI(input)가 항상 동기화 되어있음을 보장한다!

따라서 아래와 같은 상황에서 유용할 수 있다고 한다. (참고)

  • 데이터가 변경될때마다 인풋 validation이 필요할때
  • 신용카드, 전화번호같은 것을 입력될때마다 즉시 포맷팅이 필요한 경우

cf) textarea

일반 html 태그에서 textarea는 태그안에 값을 넣어서 사용한다

<textarea>
  Hello there, this is some text in a text area
</textarea>

근데 리액트에서는 value 속성을 사용하여 값을 부여한다.

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

그래서 한줄에 쓸 수 있는 input태그와 더욱더 유사해지게 된다!

cf) select

일반 html 태그에는 select 태그의 기본 선택 옵션을 지정할때, option 태그에 selected 속성을 주곤한다.

하지만 리액트에서는 부모인 select태그에 value 속성으로 처음에는 기본값을 전달해주고 선택된 값의 상태를 관리한다.

그래서

Use the 'defaultValue' or 'value' props on <select> instead of setting 'selected' on <option>

이라는 오류를 리액트가 띄우곤 했었나보다...

uncontrolled components

form data is handled by a React component.
The alternative is uncontrolled components, where form data is handled by the DOM itself.

그니까 controlled component에서는 폼 데이터가 리액트 컴포넌트에 의해서 관리되고,
uncontrolled component에서는 DOM이 직접 폼 데이터를 관리한다

특징

  • DOM이 source of truth를 유지하고 있다.
  • 그래서 non-react 코드와 통합할때에 더 편하다는 장점이 있음.
  • 코드 줄도 줄어들음. (quick and dirty)
    -> value={state} 이런것들이나 이벤트 핸들러를 하나하나 직접 만들어서 보낼 필요가 없고,
    그냥 DOM에서 form 데이터 값을 가져오려면 ref를 사용하면 된다.
  • 근데 잘 쓰이지 않음

cf) <input type="file" />

파일타입의 인풋은 데이터가 항상 읽기 전용이기 때문에 uncontrolled components일 수 밖에 없다!

cf) defaultValue

TLDR

  1. onChange 핸들러가 없을때에는 defaultValue 사용하기 (uncontrolled components)
  2. value를 사용하고 싶을때에는 onChange 핸들러를 넣어주기!! (controlled components)

비제어 컴포넌트를 사용할때 초기값은 지정해주고, 그 이후의 업데이트에 대해서는 제어하지 않는것이 좋다고 한다.
이럴때에, defaultValue를 쓰면, 컴포넌트 마운트 이후에 defaultValue값이 변하더라도 DOM에 업데이트 되지 않는다!

여기에서 정말 이해하기 딱 좋은 예시를 찾았다.

		<div><b>default value</b> (you can edit without changing this.state.value)</div>
        <input defaultValue={this.state.value}></input>
        
        <div><b>value</b> (you can't edit because it does not change this.state.value)</div>
        <input value={this.state.value}></input>

        <div><b>value</b> (you can edit because it has onChange method attached that changes this.state.value) <br /> <b>NOTE:</b> this will also change second input since it has attached the same state with <b>value</b> property, but won't change first input becase same state was attached as <b>defaultValue</b></div>
        <input value={this.state.value} onChange={e => this.onChange(e)}></input>
  1. defaultValue만 있으면 uncontrolled components 처럼 동작하여, 폼 데이터를 DOM이 직접 유저의 타이핑에 따라 관리하고, defaultValue를 초기값으로 지정해주기만 한다. (첫 마운트시의 this.state.value값)

    • 이때 defaultValue값이 컴포넌트의 state가 바뀌면서 변경되더라도, DOM에 업데이트 되지 않는것을 확인할 수 있다.
      (위의 코드에서 1번 인풋태그와 3번 인풋태그 비교)
  2. value값만 있으면 영원히 같은 value만 갖는다.

  3. 변경을 위해서는 onChange 이벤트 핸들러를 달아주어야 한다. -> controlled components가 됨.


참고

profile
제대로 짚고 넘어가자!🧐

0개의 댓글