왜 리액트에서 인풋값을 다룰때에는 value
속성을 이용해서 내부의 state를 전달해주어야할까?
html의 기본 input 태그를 사용할 수 있지만,
보통 이런 기본 html 폼들은 제출했을때 새로고침을 시킨다.
근데 우린 이런걸 원하지 않고 제출을 직접 커스텀하여 핸들링하고
입력된 값을 직접 다루고 싶다..!
-> 이럴때 리액트의 controlled component를 사용한다!
또한 리액트에서는 controlled components를 사용하는것을 권장하고 있다.
html의 기본 input
, textarea
, select
같은 태그는 자기 스스로 상태를 유지하고 사용자 입력을 기반으로 값을 업데이트한다.
따라서 리액트 컴포넌트와 기본 html 인풋 태그를 잘 합치면
리액트 안의 state
가 single source of truth가 되도록 할 수 있음!!
즉 리액트에서 value={state}
이렇게 value 속성을 기본 인풋 태그에 넣어주면
-> 보여지는 값(value
)을 리액트가 제어할 수 있게되고
-> single source of truth가 된다. (원래 인풋태그의 기본 value
와 리액트가 제어할 수 있는 상태값이 들어간 value
가 하나의 source(근원지?)를 가지게됨)
이게 리액트가 지향하는 방법임!
근데 왜 controlled components를 지향하는걸까?
그리고 여러개의 인풋을 다루고 싶다면
name
속성을 부여해서 e.target.name
으로 관리할 수 있따!
또한, controlled components를 사용하게되면
데이터(state)와 UI(input)가 항상 동기화 되어있음을 보장한다!
따라서 아래와 같은 상황에서 유용할 수 있다고 한다. (참고)
일반 html 태그에서 textarea는 태그안에 값을 넣어서 사용한다
<textarea>
Hello there, this is some text in a text area
</textarea>
근데 리액트에서는 value 속성을 사용하여 값을 부여한다.
<textarea value={this.state.value} onChange={this.handleChange} />
그래서 한줄에 쓸 수 있는 input태그와 더욱더 유사해지게 된다!
일반 html 태그에는 select
태그의 기본 선택 옵션을 지정할때, option
태그에 selected
속성을 주곤한다.
하지만 리액트에서는 부모인 select
태그에 value
속성으로 처음에는 기본값을 전달해주고 선택된 값의 상태를 관리한다.
그래서
Use the 'defaultValue' or 'value' props on <select> instead of setting 'selected' on <option>
이라는 오류를 리액트가 띄우곤 했었나보다...
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이 직접 폼 데이터를 관리한다
value={state}
이런것들이나 이벤트 핸들러를 하나하나 직접 만들어서 보낼 필요가 없고,ref
를 사용하면 된다.<input type="file" />
파일타입의 인풋은 데이터가 항상 읽기 전용이기 때문에 uncontrolled components일 수 밖에 없다!
- onChange 핸들러가 없을때에는 defaultValue 사용하기 (uncontrolled components)
- 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>
defaultValue
만 있으면 uncontrolled components
처럼 동작하여, 폼 데이터를 DOM이 직접 유저의 타이핑에 따라 관리하고, defaultValue
를 초기값으로 지정해주기만 한다. (첫 마운트시의 this.state.value
값)
defaultValue
값이 컴포넌트의 state
가 바뀌면서 변경되더라도, DOM에 업데이트 되지 않는것을 확인할 수 있다.value
값만 있으면 영원히 같은 value
만 갖는다.
변경을 위해서는 onChange
이벤트 핸들러를 달아주어야 한다. -> controlled components
가 됨.
참고