LoginSignup
26
16

More than 5 years have passed since last update.

pure react で `<select>` を使う

Posted at

概要

特別なライブラリを入れることなく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;

defaultValuevalueにしていると、下記のような警告が出ます。

警告メッセージ(改行追加).
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>
    );
  }
}

onChangevalueの値が正しくないと<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)の書き方でいいと思っています。
26
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
16