0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ReactでGoogleMapsAPI を使用した簡単なお店情報検索機能を作成してみる。(2)

Last updated at Posted at 2021-04-04

おはようございます。ふで ばこ です。

ReactでGoogleMapsAPI を使用した簡単なお店情報検索機能を作成してみる。(1)
https://qiita.com/hudebakononaka/items/0a1ba575ab47da0243f9

でお店情報検索機能を作成する手順について説明しました。
GoogleMapAPIを使用した単純なお店情報を検索する機能ですが、何かアプリを作るときに使える人が多いのではないかと思っています。

今回は作った機能に関して少しコードの説明をしていこうかなと思っています。コードは以下の中に入っていますので参照ください。
https://github.com/Kota-Yamaguchi/StoreSearch.git
基本的に説明するのはfront/storesearch/srcの下のソースコードで、主にGoogle Map APIに関するところのコードです。

では早速始めていきましょうか!

前提

前提意図してReactフックを使用して書いている部分がありますが、本質としてはgoogle-maps-reactの使用の解説がメインであるので、わからなくても読めるかと思います。
フックわからないからこの記事もわからない!という方は以下の記事をお読みください。
https://ja.reactjs.org/docs/hooks-intro.html

コード解説

PlacesAPI.jsは**storeName(お店の名前)setStoreInfo(お店情報を保存するセッター)**を引数にする関数です。
内容としては、お店の名前を検索情報として、GoogleMapAPIのPlacesAPIにリクエストを投げます。その結果、返却されるお店情報を保存するような動作をしています。

PlacesAPI.js

var map;
function getPlaces(storeName, setStoreInfo) {
    var tokyo = new google.maps.LatLng(35.412, 139.413);


    map = new google.maps.Map(
        document.getElementById('map'), { center: tokyo
, zoom: 15 });
    var service = new google.maps.places.PlacesService(map);
    service.findPlaceFromQuery({
        query: storeName,
        fields: ['name', 'formatted_address', 'geometry', 'place_id','photos']
    }, function (results, status) {
        if (status == google.maps.places.PlacesServiceStatus.OK) {
            // 配列となっていますが、1件しか返ってきません
            for (var i = 0; i < results.length; i++) {
                var place = results[i];
                console.log(place);
            } 
            setStoreInfo(results[0]);

        }
    });
}
export default getPlaces;

Mapオブジェクトを作成して、それを引数に、new google.maps.places.PlacesService(map)でPlacesServiceオブジェクトを作成しています。実は他のところのコードでもMapオブジェクトが作成されていて実はそっちでMapは表示しています。結構無駄なことをしているのですが、どうしてもコードを分けたくて変な書き方になっていますね。書き換えれそうなので、修正するべきですね。

このPlacesServiceオブジェクトが今回のコードで重要になってきています。このオブジェクトが持っているメソッドを使ってお店情報を検索していきます。

一番重要なところとしては以下の部分ですね。

service.findPlaceFromQuery({
        query: storeName,
        fields: ['name', 'formatted_address', 'geometry', 'place_id','photos']
    }, function (results, status) {
        if (status == google.maps.places.PlacesServiceStatus.OK) {
            // 配列となっていますが、1件しか返ってきません
            for (var i = 0; i < results.length; i++) {
                var place = results[i];
                console.log(place);
            } 
            setStoreInfo(results[0]);

        }
    });

これ読みにくいコードになっているのですが(ごめんなさい)
形としては

service.findPlaceFromQuery(queryContents, callback);

のようになっているわけですね。queryContentsで検索条件を投げて、callback関数に返却された値を渡して処理してもらう、ってことです。
今から少し解説しますが、この辺りの詳しい内容は以下のドキュメントに記載されていますので参考にしてみてください。
https://developers.google.com/maps/documentation/javascript/places#find_place_from_query

queryContentsの中身

queryContentsの中身では、queryに検索したい名称を入れます。今回はお店の名前を入れています。
fieldsに取得してきたい情報のフィールドをリストの形式で格納します。

queryContents
query: storeName,
fields: ['name', 'formatted_address', 'geometry', 'place_id','photos']

取得できるフィールドによっては料金が変わってきます。
料金のカテゴリとしては、Basic, Contact, Atmosphereの3つあります。下に行くほど高いです。
ただGoogleMapsAPIは毎月2万を超えるまでは無料で使用できるので、開発する段階では料金がかかることはないかと思います。

|カテゴリ | Fields |
| --- | --- | --- |
|Basic | formatted_address, geometry, icon, id, name, permanently_closed, photos, place_id, plus_code, scope, types |
|Contact | opening_hours |
|Atmosphere | price_level, rating, user_ratings_total |

callback関数の中身

callback関数では二つの結果を受け取り、処理が実行されています。受け取る値は以下のです。

  • status : レスポンスの状態(検索がしっかりできた、や取得できた件数が0件である ...など)
  • results : 取得してきた内容
callback関数
function (results, status) {
        if (status == google.maps.places.PlacesServiceStatus.OK) {
            // 配列となっていますが、1件しか返ってきません
            for (var i = 0; i < results.length; i++) {
                var place = results[i];
                console.log(place);
            } 
            setStoreInfo(results[0]);
        }
    }

関数としては、まずstatus==google.maps.places.PlacesServiceStatus.OKでレスポンスが無事返却されてきているかを確認しています。statusの確認はgoogle.maps.places.PlacesServiceStatus.OKだけでしか確認していませんが、色々あります。
例えばstatus==google.maps.places.PlacesServiceStatus.ZERO_RESULTSなどで条件分岐を作っておけば、取得件数が0件のときの処理ができたりします。
statusコードは以下のリンクに記載されているので、使用用途に合わせて参照してください。
https://developers.google.com/maps/documentation/javascript/places#place_search_responses

その下のfor文で取得した内容をコンソールに表示するようにしています。特に意味はありません。
配列で返されますが、一件しか返却されないです。まあ他のメソッドで複数件数返すものがあるので、ロジックをそちらに合わせているのだと思います。
他のメソッドと合わせて配列で返してもらった方が、他のメソッドを使用したときにも同じロジックで処理できるので便利でありがたいですね。

最後にsetStoreInfoにresults[0]を格納しています。results[0]なのは一件しか返ってこないのがわかっているのでそうしています。

Places Serviceの他のメソッド

今回使用しているメソッドはfindPlaceFromQueryですが、他にもライブラリーとしてたくさん使用できるものがあります。
使用用途に応じて、探してみてください。以下に色々と載っています。
https://developers.google.com/maps/documentation/javascript/reference/places-service#PlacesService.findPlaceFromQuery

お店情報の表示

最後に取得した情報を表示させます。
最後にsetStoreInfoにresultsを格納していますので、以下のコードではresultsの内容はstoreInfoに格納されていることを前提に以下のコードを見てください。

StoreDetail.js

<Typography>
お店検索: <TextFild className={classes.TextFild} onChange={onNameChange} variant="outlined" label="お店の名前を入力してください" />
</Typography>
<Button onClick={onNameClick} variant="contained" color="primary"> get INFO </Button>
{storeInfo &&
	<div>
		<Card>
		<CardHeader title={storeInfo["name"]} />
			<CardContent>
				<Typography> 住所: {storeInfo["formatted_address"]} </Typography>
			</CardContent>
			<img src={storeInfo.photos[0].getUrl({ 'maxWidth': 500, 'maxHeight': 500 })} alt="image" />
		</Card>
	</div>
}

以下でまず住所を表示しています。これはそこまでおかしくないですね

<Typography> 住所: {storeInfo["formatted_address"]} </Typography>

少しつまずいたのが、写真を表示させるときです。以下の内容に書いているように、
https://developers.google.com/maps/documentation/places/web-service/photos

"photos" : [
   {
      "html_attributions" : [],
      "height" : 853,
      "width" : 1280,
      "photo_reference" : "CnRvAAAAwMpdHeWlXl-lH0vp7lez4znKPIWSWvgvZFISdKx45AwJVP1Qp37YOrH7sqHMJ8C-vBDC546decipPHchJhHZL94RcTUfP~"
   }
...

のようになっていると思っていたのですが、どこをどう見てもphoto_referenceが見つからなかったので、かなりつまづいた思い出があります。本来であれば、photo_referenceをもとに写真を撮ってくるリクエストを出すと言う形なのですが、なんとphotos[0].getUrlでそれを一気にやってもらえるようです。便利ですね。
なのでコードとしては以下のようになります。実際に設定するのはmaxWidthmaxHeightだけでいいですね。

<img src={storeInfo.photos[0].getUrl({ 'maxWidth': 500, 'maxHeight': 500 })} alt="image" />

photos[0].getUrlに関してですが、どこでそれを発見したのかリソースを探し直したのですが、少し前のこともありどこにあったか見つかりませんでした。すいません。

最後に

コード全部を解説とまでは大変なのでしませんが、説明したかったところは説明しました。GoogleMapsAPIに関しては色々とリソースがありますので、勉強に関してはあまり困ることはありませんね。

0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?