概要
特別なライブラリを入れることなくHTMLの<select>をReactで動くようにします。
サンプル
ネット通販などで時間帯指定をする場面を例にしています。
create-react-app で開始しています。
App.js
import React, { Component } from 'react';
import SelectPlain from './components/SelectPlain';
import SelectPlainOnChange from './components/SelectPlainOnChange';
import SelectDynamicOptions from "./components/SelectDynamicOptions";
class App extends Component {
render() {
return (
<div>
<h1>お届け時間帯</h1>
<div>(1) <SelectPlain/> </div>
<div>(2) <SelectPlainOnChange/> </div>
<div>(3) <SelectDynamicOptions/> </div>
</div>
);
}
}
export default App;
(1) 静的な<select>の例
reactを使う意味がないとか言わない。
初期値はvalueではなくdefaultValueを使います。
import React, { Component } from 'react';
class App extends Component {
render() {
return (
<select defaultValue="14to16">
<option value="9to12">9:00-12:00</option>
<option value="12to14">12:00-14:00</option>
<option value="14to16">14:00-16:00</option>
<option value="16to18">16:00-18:00</option>
<option value="18to20">18:00-20:00</option>
<option value="20to21">20:00-21:00</option>
</select>
);
}
}
export default App;
defaultValueをvalueにしていると、下記のような警告が出ます。
警告メッセージ(改行追加).
Warning: Failed form propType:
You provided a `value` prop to a form field without
an `onChange` handler. This will render a read-only field.
If the field should be mutable use `defaultValue`.
Otherwise, set either `onChange` or `readOnly`.
onChangeを使う場合は(2)のようにしてください。
(2) (1)でdefaultValueを使わない例
valueを使ったときの警告メッセージに「onChangeを使え」とあるので、こちらで実装します。
SelectPlainOnChange.js
import React, {Component} from 'react';
export default class SelectPlainOnChange extends Component {
constructor(props) {
super(props);
this.state = {
selectedValue: '14to16'
};
}
render() {
return (
<select
value={this.state.selectedValue}
onChange={ e => this.setState({selectedValue: e.target.value}) }>
<option value="9to12">9:00-12:00</option>
<option value="12to14">12:00-14:00</option>
<option value="14to16">14:00-16:00</option>
<option value="16to18">16:00-18:00</option>
<option value="18to20">18:00-20:00</option>
<option value="20to21">20:00-21:00</option>
</select>
);
}
}
onChangeやvalueの値が正しくないと<select>をクリックして変更しても値が変わらない、という現象に遭遇します。
(3) <option>の繰り返しを排除する
(1)をリファクタリングして、<option>の繰り返しを排除します。
繰り返しの中で異なる部分はvalue属性とoption要素値なので、これらをdataという名前でオブジェクトに格納します。
import React, {Component} from 'react';
export default class SelectDynamicOptions extends Component {
constructor(props) {
super(props);
this.data = [
{ value: '9to12', label: '9:00-12:00' },
{ value: '12to14', label: '12:00-14:00' },
{ value: '14to16', label: '14:00-16:00' },
{ value: '16to18', label: '16:00-18:00' },
{ value: '18to20', label: '18:00-20:00' },
{ value: '20to21', label: '20:00-21:00' },
];
}
render() {
return (
<select defaultValue="14to16">
{ this.data.map( d => <option value={d.value}>{d.label}</option>)}
</select>
);
}
}
実用的には、constructor内でpropsを受け取りthis.dataに渡す感じになりますね。
まとめと雑記
- Reactに不慣れなのでHTMLっぽく書いてReactに移すという順序で書いていますが、意外とつまづいたので記事にしました。
- 外部ライブラリreact-selectを使ってみたものの、多要素とかぶったときに
<option>が隠れてしまってウオオとなったのが本当の動機です。あと外部依存はできるだけ少なくしたい。 - 個人的には動的に
<option>の数や属性を変えたいという要件が出るまでは(1)の書き方でいいと思っています。