こんにちは、mabuiです。
前回、reactのレンダリング処理を説明しましたが、
それを使いつつ、javascriptの非同期通信でcoinmarketcapのapiを叩いて
仮想通貨ランキング上位10銘柄の情報を取得し、
簡単なhtmlのテーブル構造で出力するサンプルを作成していきます。
coinmarketcapとは?
coinmarketcapは仮想通貨の全銘柄を独自ランキング順に閲覧できるサイトです。
Cryptocurrency Market Capitalizations | CoinMarketCap
apiを公開しており、仮想通貨情報の取得がプログラムから容易なため、
今回こちらのapiを使用して、仮想通貨上位10銘柄の情報を取得します。
https://api.coinmarketcap.com/v2/ticker/?limit=10&sort=rank
javascriptでのPromiseを使用した非同期通信
実行した処理を応答が返るまで待つ同期通信とは違い、
非同期通信では処理を投げた後に次の処理を始めます。
そのため応答を受け取るタイミングが不確定で扱いが難しくなります。
今回サンプルで使用しているisomorphic-fetchというライブラリのfetchメソッドでは、
非同期通信を行い、外部のapiにリクエストを送っています。
fetchの返り値にはPromiseオブジェクトが返ってきます。
Promiseオブジェクトではthenメソッドを使うことで返り値に対して
順序立てて処理を実行することが可能です。
サンプルではコンストラクタ内で非同期通信を行うメソッドを実行していますが、
そのままだとレンダリング中に応答が返ってこないためレスポンスの表示ができません。
setTimeoutメソッドを使って通信の実行を少し遅らせることでsetStateメソッドが反応して
2回目のレンダリングが実行されます。
サンプルコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
import fetch from 'isomorphic-fetch'; import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; // Appコンポーネント作成 class App extends React.Component { renderCoins() { // coinmarketcapから上位10位の銘柄取得api let endpoint = "https://api.coinmarketcap.com/v2/ticker/?limit=10&sort=rank" // fetchでリクエストを投げる。非同期処理でPromiseのオブジェクトが返却される。 let dict = {}; fetch(endpoint).then((response) => { let json = response.json(); json.then((value) => { let data = value.data; for (let key in data) { let coin = data[key]; let quotes_usd = coin['quotes']['USD']; // レスポンスを連想配列に詰める。 dict[coin.rank] = <li>{coin['rank']} : {coin['name']}, [price_usd: {quotes_usd['price']}], [market_cap_usd: {quotes_usd['market_cap']}], [percent_change_24h: {quotes_usd['percent_change_24h']}]</li> } }) }, (error) => { console.error(error); }).then(() => { // setTimeoutで非同期処理の結果(dict)が帰ってくるのを待つ。 setTimeout(() => { let list = []; // rank順に並び替え for(let rank in dict) { list.push(dict[rank]); } // stateが更新されたら、render()が自動的に実行される。 this.setState({ list: list }); }, 100) }) }; constructor() { super(); // Promiseは結果をそのまま返せないので、stateを用意して結果を格納しておく this.renderCoins(); this.state = { list: [] } } render() { return <ul>{this.state.list}</ul> } } ReactDOM.render( // Appコンポーネントをレンダリング <div> <App /> </div>, document.getElementById('root') ) |
出力結果
ソースコードを実行すると、画像のようにリスト形式で
仮想通貨のファンダメンタル情報が表示されます。
おわりに
いかがでしたでしょうか?
reactのコア機能であるrenderを使って実際にプログラムを作成するイメージが掴めたかと思います。
今回は基本的な機能しか扱っていませんが、これをベースにreact関連のモジュールを追加して
いけば、より実用的なプログラムになっていくと思います。
追記
Reactに用意されているcomponentWiiMountメソッドを使用して
setState()すれば、更新後の値を使用して一度だけrenderが実行されるとのことで
試してみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
componentWillMount() { this.renderCoins(); } constructor() { super(); // Promiseは結果をそのまま返せないので、stateを用意して結果を格納しておく //this.renderCoins(); this.state = { list: [] } } |
確かにコンストラクタと同じく出力はうまくいきましたが、renderは二度呼ばれるようで、
setTimeoutを使用しなくても二度呼ばれました(出力はうまくいかない)。
非同期通信の場合だと勝手が違うようです。