フォーム
フォーム要素はReactにおいて他のDOM要素と少し異なる動作をします
制御されたコンポーネント
HTMLではフォーム要素は通常、自身で状態を保持しており、ユーザの入力に基づいてそれを更新します。 Reactでは、変更されうる状態は通常コンポーネントのstateプロパティに保持され、setState()関数でのみ更新されます。
Reactのstateを信頼できる唯一の情報源とすることで、上述の2つの状態を結合させることが出来ます。そうすることで、フォームをレンダーしているReactコンポーネントが、後続するユーザー入力で起きることも制御出来るようになります。 このような方法で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 submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
{/* valueはReactのstateをonChange時に更新した状態のものを利用する */}
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
</form>
);
}
}
textareaタグ
Reactでは<textarea>
はvalue属性を使用する
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('A 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>
);
}
}
selectタグ
Reactではselected
属性の代わりに、value
属性を親のselect
タグで使用します
class FlavorForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: "cocount"};
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>
);
}
}
file input タグ
値はユーザだけが設定可能で、プログラムでは操作できないため、Reactでは非制御コンポーネントになる。
ファイルをやり取りする場合、File APIを使用する
class FileInput extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.fileInput = React.createRef();
}
handleSubmit(event) {
event.preventDefault();
alert(
`Selected file - ${
this.fileInput.current.files[0].name
}`
);
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Upload file:
<input type="file" ref={this.fileInput} />
</label>
<button type="submit">Submit</button>
</form>
);
}
}
ReactDOM.render(
<FileInput />,
document.getElementById("root")
);
複数の入力の処理
複数の制御されたinput要素を処理する必要がある場合、それぞれの入力要素にname属性を追加すれば、ハンドラー関数にevent.target.name
に基づいて処理を選択させるように出来る
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
});
}
return() {
return (
<form>
<label>
Is going:
<input
name="isGoing"
type="checkbox"
checked={this.state.isGoing}
onChange={this.handleInputChange}
/>
</label>
<label>
Number of guests:
<input
name="numberOfGuests"
type="number"
checked={this.state.numberOfGuests}
onChange={this.handleInputChange}
/>
</label>
</form>
);
}
}