【React】inputとかselectとかフォームで使う部品の利用方法

フォームでよく使う部品(input,textarea,checkbox,radio,selectなどなど)のreact上での取り扱い方がよくわからなかったので、取りあえず動くサンプルを作ろうと思った。

参考

フォーム – React
ユーザインターフェース構築のための JavaScript ライブラリ

環境

【OS】
$ cat /etc/redhat-release
CentOS Linux release 8.2.2004 (Core)

【Node.js】
$ node --version
v12.18.2

【React】
$ npm list --depth=0
my@0.1.0 /home/vagrant/my
├── @reduxjs/toolkit@1.4.0 extraneous
├── @testing-library/jest-dom@5.11.5
├── @testing-library/react@11.1.0
├── @testing-library/user-event@12.1.10
├── react@17.0.1
├── react-dom@17.0.1
├── react-scripts@4.0.0
└── web-vitals@0.2.4

やったこと

テキストボックスをjsxにおいただけだと、文字入力すらできなかったので文字入力できるようにしようと思った。

どうやら、reactではテキストボックスのようなユーザーから入力を受け取るタイプのものは、値が入力されるたびにstateに値を保存してそれを表示させるという形式で更新されるらしい。

なので、コード書かないと1文字も入力できないようだ。チェックボックスなんかクリックしても何も起きない。
テキストエリアに文字をうつと、いくらキーボードを叩いても文字が表示されないとかいうhtmlっぽくない現象が起きる。

とりあえず各input系部品に下記の属性を設定して更新できるようにする。

name: name属性の値と同名のstateを更新するのに使うので書いておく
value: value属性の値でstateを更新して、更新したstateがvalue属性に戻したりする
onChange: value値の更新を検知したら更新用関数を動かしてstateが更新されるようにする

onChange時に発火する更新用関数はcheckbox用とそれ以外で下記の2種類用意した。
(チェックボックスに初期値を設定すると入力が受け付けられないので反転させなければいけなかったためチェックボックス用の関数を作った、なにかほかにもっといい方法があるのかも…)

handleCheckboxChange(event)
handleInputChange(event)

できたアンケートは下記のような感じ。
CSSとか入れてないので、ひとまずフォームに入力、選択ができればいいやという気持ちで作成した。
※初期値設定がしたかったので、初期値はめちゃくちゃにしておいた。

入力フォームのサンプルのApp.jsコード

下記記事の作業後にApp.jsを記載したコードに入れ替えれば動くはず…。

【React】CentOS8.2で環境構築してレンタルサーバーにデプロイする
Node.jsとReactを使ってなんかやることになったのでCentOS8.2にインストールして開発環境をつくった。 ついでにReactのチュートリアルをビルドして普通のレンタルサーバーにデプロイしてみる。 環境 【OS】Microsoft...
import React from 'react';

class App extends React.Component {
  // stateを使わないとinputに文字が表示できないのでコンストラクタで宣言しておく
  constructor(props) {
    super(props);
    // formに初期値を設定したい場合は書いておく
    this.state = {
      fullname:"",
      pref:"47",
      gender: "custom",
      remarks:"初期備考",
      confirm: "1",
    };

    // thisをbindしないとthis.setStateが読み取れないらしく「TypeError: Cannot read property 'setState' of undefined」とエラーが出るのでbindしておく
    this.handleInputChange = this.handleInputChange.bind(this);
    this.handleCheckboxChange = this.handleCheckboxChange.bind(this);
  }
  
  // input,textarea,select,radioのonChangeイベント発生時
  handleInputChange(event) {
    const target = event.target;

    // name属性の値を取得
    const name = target.name;

    // name属性の値と同じ名前のstateを、現在入力されている値に更新する
    this.setState({
      [name]: target.value
    });
  }
  
  // checkboxのonChangeイベント発生時
  handleCheckboxChange(event) {
    const target = event.target;
    const name = target.name;

    // チェックボックスの入力値を反転させる
    this.setState({
      [name]: this.state.confirm === "1" ? "0" : "1"
    });
  }

  // 「名前を呼ぶボタン」のクリック時動作
  handleClick(){
    const user = this.state.fullname;

    // 名前があればアラートを表示する
    if(user !== ""){
      alert("やあ "+ user + " さん!");
    }else{
      alert("名前を入力してください");
    }
  }

  render() {
    // htmlを埋め込む場合は「__html」属性のあるオブジェクトに入れたい値を入れる
    const lable = {__html:"<h1>アンケート</h1>"};

    // formの送信先URL
    const actionUrl = "http://192.168.33.99/form.php";

    return ( 
    <form action={ actionUrl } method="get">

      {/** htmlを埋め込む(エスケープされないので注意) */}
      <div dangerouslySetInnerHTML={ lable }></div>

      {/**テキストボックス */}
      <div>
      <label htmlFor="fullname">名前:</label>
        <input name="fullname" id="fullname" value={ this.state.fullname } onChange={this.handleInputChange} autoComplete="false"/>
      </div>
  

      {/**ラジオボタン */}
      <div>
        <label>性別:</label>
        <input type="radio" id="man" name="gender" value="man" checked={this.state.gender === 'man'}  onChange={this.handleInputChange}/>
        <label htmlFor="man">男性</label>
        
        <input type="radio" id="woman" name="gender" value="woman" checked={this.state.gender === 'woman'} onChange={this.handleInputChange}/>
        <label htmlFor="woman">女性</label>
        
        <input type="radio" id="custom" name="gender" value="custom" checked={this.state.gender === 'custom'}  onChange={this.handleInputChange}/>
        <label htmlFor="custom">その他</label>
      </div>

      {/**セレクトボックス */}
      <div>
      <label htmlFor="pref">都道府県:</label>
        <select name="pref" id="pref" value={this.state.pref} onChange={this.handleInputChange}>
        <option value=""></option>
          <option value="1">北海道</option>
          <option value="2">青森県</option>
          <option value="3">岩手県</option>
          <option value="4">宮城県</option>
          <option value="5">秋田県</option>
          <option value="6">山形県</option>
          <option value="7">福島県</option>
          <option value="8">茨城県</option>
          <option value="9">栃木県</option>
          <option value="10">群馬県</option>
          <option value="11">埼玉県</option>
          <option value="12">千葉県</option>
          <option value="13">東京都</option>
          <option value="14">神奈川県</option>
          <option value="15">新潟県</option>
          <option value="16">富山県</option>
          <option value="17">石川県</option>
          <option value="18">福井県</option>
          <option value="19">山梨県</option>
          <option value="20">長野県</option>
          <option value="21">岐阜県</option>
          <option value="22">静岡県</option>
          <option value="23">愛知県</option>
          <option value="24">三重県</option>
          <option value="25">滋賀県</option>
          <option value="26">京都府</option>
          <option value="27">大阪府</option>
          <option value="28">兵庫県</option>
          <option value="29">奈良県</option>
          <option value="30">和歌山県</option>
          <option value="31">鳥取県</option>
          <option value="32">島根県</option>
          <option value="33">岡山県</option>
          <option value="34">広島県</option>
          <option value="35">山口県</option>
          <option value="36">徳島県</option>
          <option value="37">香川県</option>
          <option value="38">愛媛県</option>
          <option value="39">高知県</option>
          <option value="40">福岡県</option>
          <option value="41">佐賀県</option>
          <option value="42">長崎県</option>
          <option value="43">熊本県</option>
          <option value="44">大分県</option>
          <option value="45">宮崎県</option>
          <option value="46">鹿児島県</option>
          <option value="47">沖縄県</option>
        </select>
      </div>
      
      {/**テキストエリア */}
      <div>
      <label htmlFor="remarks">備考:</label><textarea name="remarks" id="remarks" value={this.state.remarks} onChange={this.handleInputChange} />
      </div>

      {/**チェックボックス */}
      <div>
      <label htmlFor="confirm"><a href="http://192.168.33.99" target="_blank">利用規約</a>への同意:</label>
      <input type="checkbox" name="confirm" id="confirm" value="1"  checked={this.state.confirm === "1"} onChange={this.handleCheckboxChange}/>
      </div>


      {/**ボタン */}
      <div>
        <button onClick={ ()=>this.handleClick() } type="button">名前を呼ぶボタン</button> <input type="submit" value="送信" /> 
      </div>
    </form>
      
    );
  }
}

export default App;

おわり。