form

Forms

forms 엘리먼트는 자체가 내부 상태를 가지기 때문에 React의 다르 DOM 엘리먼트와 들게 동작한다.

1
2
3
4
5
6
7
<form>
<label>
Name:
<input type="text" name="name" />
</label>
<input type="submit" value="Submit" />
</form>

기본적으로 폼을 제출하면 새로운 페이지로 이동하는 동작을 수행한다. 원한다면 사용하면 되는데 일반적으로는 Javascript를 통해서 제출을 처리하고 사용자가 입력한 값에 접근하는 방법을 사용한다. 이런 방법을 사용하기 위해서는 controlled components 라고 불리는 기술을 사용해야 한다.

Controlled Components

일반적으로 html 에서 input, textarea, selct와 같은 폼 엘리먼트는 사용자의 입력을 기반으로 자신의 state를 관리하고 업데이트 한다. React서는 setState를 해야 state를 변경할 수 있으므로 사용자의 입력을 철리하려면 관리하는 state를 추가해야 한다.
React에 의해 값이 제어되는 입력 폼 엘리먼트를 controlled component라고 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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>
);
}
}

코드를 조금 더 생성해야 하긴 하지만, 다른 이벤트에 의해서 값을 초기화 할 수 도 있고 전달 할 수 있어서 편리하다.

textarea 태그

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

html 에서는 textarea 테그는 자식 요소로 text를 받아서 자신의 value로 사용한다. react 에서는 value에 어트리뷰트로 추가해여 똑같이 동작 시킬 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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>
);
}
}

The select Tag

html 에서 select는 드롭다운 메뉴를 만든다.

1
2
3
4
5
6
<select>
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option selected value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>

selected 옵션을 사용하여 초기에 선택되는 값을 정하는데 리엑트에서는 select 태그에 value 옵션을 줌으로써 똑같이 동작시킬 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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>
</label>
<input type="submit" value="Submit" />
</form>
);
}
}

select 태그에 multiple 옵션을 허용한다면 value 어트리뷰트에 배열을 전달할 수 잇다.

1
<select multiple={true} value={['B', 'C']}>

file input 태그

HTML 에서 input 태그에 type 을 file 로 설정하여 파일을 입력 받을 수 있다.
값은 읽기 전용 이기때문에 React 에서는 이를 비제어 컴포넌트라고 부른다.

1
<input type="file" />

다중 입력 제어하기

다중 입력을 제어할때 입력 태그에 name 을 주어서 구분 할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
class Reservation extends React.Component {
constructor(props) {
super(props);
this.state = {
isGoing: true,
numberOfGuests: 2,
};

this.handleInputChange = this.handleInputChange.bind(this);
}

handleInputChange(event) {
const target = event.target;
const value = target.type === "checkbox" ? target.checked : target.value;
const name = target.name;

this.setState({
[name]: value,
});
}

render() {
return (
<form>
<label>
Is going:
<input
name="isGoing"
type="checkbox"
checked={this.state.isGoing}
onChange={this.handleInputChange}
/>
</label>
<br />
<label>
Number of guests:
<input
name="numberOfGuests"
type="number"
value={this.state.numberOfGuests}
onChange={this.handleInputChange}
/>
</label>
</form>
);
}
}

Controlled Input Null Value

value props 를 주면은 사용자가 값을 변경할 수 없다. React에서 state로 관리해야 그때부터 변경할 수 있게 된다. 그런데 value prop으로 null 이나 undifiend를 주면 state를 관리하지 않아도 사용자가 변경할 수 있게 된다.

1
2
3
4
5
ReactDOM.render(<input value="hi" />, mountNode);

setTimeout(function () {
ReactDOM.render(<input value={null} />, mountNode);
}, 1000);

Alternatives to Controlled Components

사실 제어 컴포넌트를 사용하느것이 해보면 좀 귀찮은 작업이라는 것을 알게 된다. 또한 다른 앱을 리액트 앱으로 바꾸려 할때에도 이는 정말로 귀찮은 작업으로 다가올 수 있다. 이때 대안으로 사용할 수 있는 비제어 컴포넌트가 있는데 자세한건 홈페이지에서 문서를 찾아 보길 바란다.

Fully-Fledged Solutions

Formik 이 완벽한 해결을 줄수 있다. 근데 이것도 기본적인 원칙은 위에서 설명한 것과 같기 때문에 기본적인 원칙을 모르면 어렵다. 기본적인 원칙을 공부하길 바란다.