概要
特別なライブラリを入れることなく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)の書き方でいいと思っています。