폼
제어 컴포넌트 (Controlled Componenet)
HTML에서 <input>, <textarea>, <select>와 같은 폼 엘리먼트는 일반적으로 사용자의 입력을 기반으로 자신의 state를 관리하고 업데이트한다. 여기서 눈치챈 사람들도 많을 것이다. 자신의 state를 관리하면 되므로 클래스형 컴포넌트를 사용해 setState()로 상태를 업데이트 하면 된다.
"제어 컴포넌트 (controlled component)"는 React에 의해 값이 제어되는 입력 폼 엘리먼트를 말한다.
아래 코드를 보며 제어 컴포넌트를 알아보자.
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 sumitted: ' + 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>
);
}
}
ReactDOM.render(<NameForm />, document.getElementById('root'));
먼저 22번째 줄을 주목해보자. 나는 onSubmit을 하단의 submit 버튼에 주어야 한다고 생각했는데 이는 잘못된 생각이었다. form이 제출된 후 발생할 이벤트기 때문에 form에 onSubmit으로 주어야 한다.
그리고 이벤트가 발생한 곳의 value는 event.target으로 접근하는 것을 보면 좋을 것이다.
우리가 constructor 내부에 this.state를 선언하는 곳에서 value의 값을 임의로 주면 어떻게 될까?? 화면에 <input type="text"> 부분에 우리가 설정한 값이 생길 것을 예상했다면 이 부분은 확실하게 이해한 것이라고 생각해도 좋다.
textarea 태그
textarea 태그에 대해서는 위에 설명한 부분과 너무 똑같다. 마지막에 내가 한 질문에 대답을 할 수 있다면 여기도 똑같은 설명을 써놓은 것을 알 수 있을 것이다.
아래 코드를 보고 확인하자.
class EssayForm extends React.Component {
constructor(props) {
super(props);
this.state = {
value: 'Please write an essay about your favorite DOM element.'
}
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('An essay was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return(
<form onSubmit={this.handleSubmit}>
<label>
Essay:
<textarea value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
)
}
}
ReactDOM.render(
<EssayForm />,
document.getElementById('root')
);
5-7 줄에서 state의 value를 설정하는 부분과 결과 화면을 비교해서 보면 이해가 될 것이라고 믿는다. 만약 어렵다면 댓글을 달다주면 친절히 설명하도록 하겠다.
select 태그
일단 아래의 HTML에서 select 태그를 사용하는 코드를 보고 가자.
<select>
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option selected value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
HTML에서 selected 옵션을 사용해 초기값을 Coconut으로 설정했다. 벌써 눈치 채셨겠지만, React에서는 초기에 state를 설정할 때 value를 coconut으로 주어 초기값을 Coconut으로 설정할 수 있다.
아래 코드를 보자.
class FlavorForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: 'coconut'};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('Your favorite flavor is: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Pick your favorite flavor:
<select value={this.state.value} onChange={this.handleChange}>
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
<input type="submit" value="Submit" />
</label>
</form>
);
}
}
ReactDOM.render(<FlavorForm />, document.getElementById('root'));
select 태그 안에 value 값으로 우리가 초기화한 state의 value를 넣어주면 해당 값이 첫 화면에 나타나는 것을 확인할 수 있다.
다중 입력 제어하기
가장 어렵지만 중요하지는 않은, 그렇지만 알면 정말 유용하게 쓸 수 있는 부분이다. 약간의 수학적(?), 프로그래밍적(?)인 사고만 있다면 쉽게 이해할 수 있겠지만, 나같은 사람들도 조금만 생각하면 이해 가능하다.
두 개 이상의 input 태그를 사용했을 때, 각각의 값을 어떻게 제어할 것인지에 대한 내용이다. 그냥 state를 2개 만들면 안되나? 라고 생각했다면 좋은 프로그래머일 것이다 ㅎㅎ. 이번에는 하나의 state로 다중 입력을 제어하는 것을 알려준다.
코드를 보자.
class Reservation extends React.Component {
constructor(props) {
super(props);
this.state = {
isGoing: true,
numberOfGuests: 2
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
handleSubmit(event) {
alert('Is going: ' + this.state.isGoing + '\n number of guests: ' + this.state.numberOfGuests);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Is going:
<input type="checkbox" name="isGoing" checked={this.state.isGoing} onChange={this.handleChange} />
</label>
<br />
<label>
Number of guests:
<input type="number" name="numberOfGuests" value={this.state.numberOfGuests} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
)
}
}
ReactDOM.render(<Reservation />, document.getElementById('root'));
먼저 16번 줄을 보면 target의 타입에 따라 value가 target의 checked 값을 가질지, value 값을 가질지가 결정된다.
이후 19번 줄에서 ES6의 객체 속성 접근을 사용해 name이 객체의 key가 되도록 설정한다.
가장 중요한 부분은 33번과 39번 줄에서 input 태그에 name을 준 부분이다. 해당 name으로 이벤트 핸들러가 값에 접근할 수 있게 된다.