JavaScript
React

React.jsでボタンをおしたら何かを表示するやつを試行錯誤しながらサンプルに追加するチュートリアル その2

これはなに?

React.jsでボタンをおしたら何かを表示するやつを試行錯誤しながらサンプルに追加するチュートリアル のその2です。

前回までで、ボタンをおしたら外部のAPIをたたいて結果を表示するようなサンプルができあがっています。
今度は、前回説明を省略した thisstate について説明しつつサンプルを変えていきます。

前回から、不要なHTMLの削除や、テキストやコメントを変えているのでご注意ください

下記のコードでApp.jsを書き換えてからnpm startでサーバを動かして、ブラウザで確認してみましょう。
前回同様の動きになったら次に行ってみましょう。

src/App.js
import React, { Component } from 'react';
import './App.css';

class App extends Component {
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <a onClick={this.handleClick}>住所を表示</a>

          <p>{this.state.tenki}</p>

        </header>
      </div>
    );
  }
  handleClick() {
    fetch('https://api.zipaddress.net/?zipcode=1000005', {
      mode: 'cors'
    })
    .then(res => {
      return res.json();
    })
    .then(json => {
      this.setState({tenki:json.data.fullAddress});
    })
  }

  constructor(props) {
    super(props);
    this.state = { tenki : "まだ住所をとってません" };
    this.handleClick = this.handleClick.bind(this);
  }
}

export default App;

状態遷移とかデータの受け渡しとかをしてみる

さて、前回に加えて、もう少しReact.jsっぽいことをチュートリアル的にやってみます。

「郵便番号」の入力ができるようにして、「住所を表示」を押すと、該当の住所が表示される

前回がボタンを押すだけだったのに対して、今回は入力のフォームもつけてみました。

「郵便番号」の入力テキストボックスをつける!

src/App.js
import React, { Component } from 'react';
import './App.css';

class App extends Component {
  render() {
    return (
      <div className="App">
        <header className="App-header">
          {/* ***** テキストボックス ***** */}
          <p>郵便番号をいれてください</p>
          <p><input type="text" value={this.state.zip_code} /></p>
          {/* ***** ここまで ***** */}

          <a onClick={this.handleClick}>住所を表示</a>

          <p>{this.state.tenki}</p>

        </header>
      </div>
    );
  }
  handleClick() {
    // クエリにinputされたzip_codeを使う
    fetch('https://api.zipaddress.net/?zipcode=' + this.state.zip_code, {
      mode: 'cors'
    })
    .then(res => {
      return res.json();
    })
    .then(json => {
      this.setState({tenki:json.data.fullAddress});
    })
  }

  constructor(props) {
    super(props);
    // **** 住所を扱うために zip_code という値をstateに追加
    this.state = { tenki : "まだ住所をとってません", zip_code : '1000005' };
    this.handleClick = this.handleClick.bind(this);
  }
}

export default App;

追加したところ少し詳しく見てみます。
まず<input>タグを追加しています。これは単なるHTMLなので問題ないですね。inputvalue には {this.state.zip_code} という変数を指定しているところだけ注意です。

valueに使ったthis.state.zip_codeという変数ですが、勝手に使うわけにもいかないので、コンストラクタのところで、this.state =...zip_code の初期値を追加してあります。

そして、最後に、この zip_code の値がAPIのクエリに使われるようにするために、fetchのクエリ(URL)書き換えています。

 image.png

ということで実際起動してクリックしてみるとこんな感じになります。

あれ値が書き換わらないぞ?

やってみればわかりますが、このままだとinputのところを書き換えようとしても値が書き換わりません。

なぜかというと、valueの値がthis.state.zip_codeになっているからです。

どれだけテキストボックス上で値を書き換えようとしても、valueの値はthis.state.zip_codeになり続けるので、変わることができないのです。 inputには、初期値で入力されたthis.state.zip_codeが表示され続けてしまいます。

ということで、どうするかというと、要は this.state.zip_code を変えてあげればいいのです。

値が変わるようにする

    :
          <p><input type="text" value={this.state.zip_code} onChange={(e) => this.setState({zip_code: e.target.value})} /></p>
    :

inputonChange={(e) => this.setState({zip_code: e.target.value})}を追加します。

つまり何をしているかというと、inputの値がかわるonChangeイベントを使って、値が変わるたびにsetStateを呼び出して値を書き換えていくのです。

これで、無事に値を書き換えることが出来ます。

実際に動かして、郵便番号を変えて住所をとってきてみましょう。

エラー処理してないので存在しない番号をいれてもエラーもなにもでてきません^^

ちょっとだけ色気を出して

値によって処理を変えます。

まあ、たいしたことはしません。 住所が 東京 だったときだけ色を変えるというだけです。

src/App.js
import React, { Component } from 'react';
import './App.css';

class App extends Component {
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <p>郵便番号をいれてください</p>
          <p><input type="text" value={this.state.zip_code} onChange={(e) => this.setState({zip_code: e.target.value})} /></p>

          <a onClick={this.handleClick}>住所を表示</a>

          {/* ***** p に style を指定 ***** */}
          <p style={this.state.address_style}>{this.state.tenki}</p>

        </header>
      </div>
    );
  }
  handleClick() {
    fetch('https://api.zipaddress.net/?zipcode=' + this.state.zip_code, {
      mode: 'cors'
    })
    .then(res => {
      return res.json();
    })
    .then(json => {
      // 東京という文字がはいっているかどうかで style を変更
      if ( json.data.fullAddress.indexOf('東京') !== -1 ){
        this.setState({address_style:{color:"red"}})
      }
      else {
        this.setState({address_style:{color:"white"}})
      }
      this.setState({tenki:json.data.fullAddress});
    })
  }

  constructor(props) {
    super(props);
    this.state = { tenki : "まだ住所をとってません", zip_code : '1000005', address_style : {} };
    this.handleClick = this.handleClick.bind(this);
  }
}

export default App;

まあ、こんな感じです。

こういうところ1つとってもReact(JSX)はちょっとずつクセがありますね。
style って普通は文字列で指定する属性ですけど、JSXでは {} になってますよね、こういう微妙な差異がなかなか慣れるまでは難しいところです。