🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Redux

Reduxは、JavaScriptアプリケーションの状態を管理するためのオープンソースライブラリです。ReactやAngularで一般的にユーザーインターフェイスの構築に利用されます。

Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

解決済

1回答

2658閲覧

ReactでGeolocation APIを使用した現在地の取得ができない。

退会済みユーザー

退会済みユーザー

総合スコア0

Redux

Reduxは、JavaScriptアプリケーションの状態を管理するためのオープンソースライブラリです。ReactやAngularで一般的にユーザーインターフェイスの構築に利用されます。

Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

0グッド

0クリップ

投稿2019/11/03 12:28

前提・実現したいこと

React+Redux+Laravelを使用して個人でアプリケーションを開発しています。
そこで、現在地を取得してGoogleMapsで表示させようと思っているのですが、なぜか現在地がでたらめな場所に表示されてしまいます。関西と関東ほどの誤差があります。
現在地の取得にはcomponentDidMount内でJS標準のGeolocation APIを使用して取得した緯度、経度をstateに保存して使用しています。GoogleMapsの表示に関してはgoogle-map-reactを使用しています。
どなたか解決方法のご教授お願いいたします。

※開発環境にはLaradocを使用しています。
※getGourmet関数に関してはホットペッパーAPIを叩いているだけですので今回は関係ないです。

該当のソースコード

JavaScript

1import React from 'react' 2import { Link } from 'react-router-dom' 3import { withStyles } from '@material-ui/core/styles' 4import GoogleMapReact from 'google-map-react' 5import * as actions from '../../actions' 6import { connect } from 'react-redux' 7import { bindActionCreators } from 'redux' 8 9import Card from '@material-ui/core/Card' 10import CardActions from '@material-ui/core/CardActions' 11import CardContent from '@material-ui/core/CardContent' 12import CardMedia from '@material-ui/core/CardMedia' 13import Button from '@material-ui/core/Button' 14import AddLocationIcon from '@material-ui/icons/AddLocation' 15import EmojiPeopleIcon from '@material-ui/icons/EmojiPeople' 16import Replay from '@material-ui/icons/Replay' 17 18 19const drawerWidth = 250 // Width for Drawer 20 21const styles = (theme) => ({ 22 root: { 23 [theme.breakpoints.up('md')]: { 24 width: `calc(100% - ${drawerWidth}px)`, 25 marginLeft: drawerWidth 26 }, 27 padding: 30, 28 }, 29 toolbar: theme.mixins.toolbar, // Minimum height of Toolbar 30 link: { 31 textDecoration: 'none' 32 }, 33 titleArea: { 34 margin: '0 auto', 35 display: 'flex', 36 justifyContent: 'center', 37 alignItems: 'center', 38 flexDirection: 'column' 39 }, 40 title: { 41 margin: '0 auto', 42 marginBottom: 20, 43 padding: 0 44 }, 45 btn: { 46 margin: 'auto', 47 textAlign: 'center', 48 }, 49 map: { 50 width: '90vmin', 51 height: '90vmin', 52 marginTop: 40, 53 marginBottom: 50, 54 margin: '0 auto' 55 }, 56 shopListTitle: { 57 textAlign: 'center' 58 }, 59 card: { 60 [theme.breakpoints.up('sm')]: { 61 width: '45%' 62 }, 63 width: '100%', 64 margin: 10, 65 }, 66 cardTitle: { 67 textDecoration: 'none', 68 color: 'black', 69 }, 70 infoTable: { 71 borderCollapse: 'collapse' 72 }, 73 info: { 74 border: 'solid 1px red', 75 padding: 5 76 }, 77 share: { 78 textDecoration: 'none', 79 color: '#bbb' 80 }, 81 more: { 82 textDecoration: 'none', 83 color: '#bbb' 84 }, 85 cards: { 86 display: 'flex', 87 flexWrap: 'wrap', 88 margin: '0 auto', 89 } 90}) 91 92const Me = () => <div><EmojiPeopleIcon /></div> 93const Pin = () => <div><AddLocationIcon /></div> 94 95class Result extends React.Component { 96 constructor(props) { 97 super(props) 98 this.state = { 99 lat: null, 100 lng: null, 101 shops: '' 102 } 103 } 104 105 render() { 106 const { classes } = this.props 107 const shops = Array.from(this.state.shops) 108 const center = { lat: this.state.lat, lng: this.state.lng } 109 110 // TODO: いいねボタン 111 return ( 112 <div className={classes.root}> 113 <div className={classes.toolbar} /> 114 <div className={classes.titleArea}> 115 <h2 className={classes.title}>周辺のお店</h2> 116 <Link to="/" className={classes.link}><Button className={classes.btn} startIcon={<Replay />} variant="outlined" color="primary">やり直す</Button></Link> 117 </div> 118 <div className={classes.map}> 119 <GoogleMapReact 120 bootstrapURLKeys={{ 121 key: '***********' 122 }} 123 center={center} 124 defaultZoom={14} 125 yesIWantToUseGoogleMapApiInternals 126 > 127 {/* 現在地 */} 128 <Me 129 lat={this.state.lat} 130 lng={this.state.lng} 131 /> 132 133 {/* 店にピンを挿す */} 134 {shops.map((shop, i) => ( 135 <Pin 136 key={i} 137 lat={shop.lat} 138 lng={shop.lng} 139 /> 140 ))} 141 </GoogleMapReact> 142 </div> 143 <h2 className={classes.shopListTitle}>お店一覧</h2> 144 <div className={classes.cards}> 145 {/* 店の情報を一覧表示 */} 146 {shops.map((shop, i) => ( 147 <Card className={classes.card} key={i}> 148 <CardMedia 149 className={classes.media} 150 image={shop.logo_image} 151 title="Contemplative Reptile" 152 /> 153 <CardContent> 154 <h2><a href={shop.urls.pc} target="_blank" className={classes.cardTitle}>{shop.name}</a></h2> 155 <p>{shop.genre.catch}</p> 156 <table className={classes.infoTable}> 157 <thead> 158 <tr><td className={classes.info}>アクセス</td><td className={classes.info}>{shop.access}</td></tr> 159 </thead> 160 <tbody> 161 <tr><td className={classes.info}>平均予算</td><td className={classes.info}>{shop.budget.average}</td></tr> 162 <tr><td className={classes.info}>飲み放題</td><td className={classes.info}>{shop.free_drink}</td></tr> 163 <tr><td className={classes.info}>食べ放題</td><td className={classes.info}>{shop.free_food}</td></tr> 164 <tr><td className={classes.info}>最大人数</td><td className={classes.info}>{shop.party_capacity}</td></tr> 165 <tr><td className={classes.info}>駐車場</td><td className={classes.info}>{shop.parking}</td></tr> 166 <tr><td className={classes.info}>open</td><td className={classes.info}>{shop.open}</td></tr> 167 </tbody> 168 </table> 169 </CardContent> 170 <CardActions> 171 <Button size="small"> 172 <a href={shop.urls.pc} target="_blank" className={classes.more}>Show More</a> 173 </Button> 174 </CardActions> 175 </Card> 176 ))} 177 </div> 178 </div> 179 ) 180 } 181 182 componentDidMount() { 183 navigator.geolocation.getCurrentPosition(pos => { 184 this.setState({ 185 lat: pos.coords.latitude, 186 lng: pos.coords.longitude 187 }) 188 189 const http = axios.create({ 190 baseURL: 'http://localhost:8000/api/gourmet', 191 timeout: 2000, 192 }) 193 194 this.props.actions.httpRequest() 195 196 // TODO: 関数化? 197 const getGourmet = async () => { 198 try { 199 const response = await http.get('', { 200 params: { 201 range: 3, 202 order: 4, 203 lat: pos.coords.latitude, 204 lng: pos.coords.longitude, 205 party_capacity: `${this.props.QuestionsReducer.people}`, 206 budget: `${this.props.QuestionsReducer.budget}`, 207 free_food: `${this.props.AmountReducer.freeFood}`, 208 free_drink: `${this.props.AmountReducer.freeDrink}`, 209 genre: `${this.props.QuestionsReducer.genre}` 210 } 211 }) 212 this.setState({ 213 shops: response.data.results.shop 214 }) 215 console.log(response.data.results.shop) 216 } catch (error) { 217 console.log(error) 218 } 219 } 220 221 getGourmet() 222 223 this.props.actions.httpSuccess() 224 }, err => { 225 this.props.actions.httpFailure() 226 console.log(err) 227 }) 228 } 229} 230 231const mapStateToProps = state => ({ 232 QuestionsReducer: state.QuestionsReducer, 233 AmountReducer: state.AmountReducer, 234 HttpReducer: state.HttpReducer 235}) 236 237const mapDispatchToProps = dispatch => ({ 238 actions: bindActionCreators(actions, dispatch) 239}) 240 241const styledResult = withStyles(styles, { withTheme: true })(Result) 242 243export default connect(mapStateToProps, mapDispatchToProps)(styledResult) 244

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jun68ykt

2019/11/03 14:22

一点、念のための確認になってしまい恐縮ですが、ご質問に挙げられているコンポーネントを表示させるときの URL は、http ではなくセキュアなhttp すなわち、 https で始まっていますでしょうか?
退会済みユーザー

退会済みユーザー

2019/11/03 14:47

ご回答ありがとうございます! httpですね! httpsでないとセキュリティ的に正しい現在地が取得できないという情報は知っていたのですが、localhostで動作させているということと、一番初めに動作させたときはしっかり位置情報を拾ってくれたので、可能性からは省いてしまったのですが、やはりこれが原因でしょうか? 当方、知識不足ですので馬鹿なことを言っているかもしれませんが、お付き合い頂けると幸いです…。
jun68ykt

2019/11/03 15:08

回答しました。参考になれば幸いです。
guest

回答1

0

ベストアンサー

こんにちは

MDN の Geolocation API の説明の一番上に、以下のように注記があります。

安全なコンテキスト用

この機能は一部またはすべての対応しているブラウザーにおいて、安全なコンテキスト (HTTPS) でのみ利用できます。

と明記されていますので、https でない限りは、意図した結果にならないと思ったほうがよいと思われます。ちなみにURLスキームが https である場合に、現在地を取得できていることは以下のように確認できます。

Geolocation API のページのURLは、

https://developer.mozilla.org/ja/docs/Web/API/Geolocation/Using_geolocation 

で、URLスキームは https です。このページをスマホのブラウザで表示させ、以下のような黄色の背景に「Show my location」というボタンのあるところまでスクロールします。

イメージ説明

そしてこのボタンをタップすると、位置情報を送信してよいかの許可を求められて、それに了解すると、現在の正確な緯度経度が表示されるかと思いますが、いかがでしょう?(私は iPhone8 を使用し、Safariで開きましたが、正確な現在地の緯度経度が表示されました)

以上、参考になれば幸いです。

投稿2019/11/03 15:07

編集2019/11/03 15:21
jun68ykt

総合スコア9058

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2019/11/03 15:27 編集

ご回答ありがとうございます! 私のMacBookのChromeでタップしてみましたが、 Unable to retrieve your location と表示されて、現在地が取得できませんね…。Safariのほうではいけました! 因みに携帯(iPhone8)では表示されているので、ネットワークの問題ではないと思います…。
jun68ykt

2019/11/03 15:31

MacBookではなくスマホで確認することはできますでしょうか?ひとつ前のご質問で、お手持ちのiPhoneでテストをしている、というようようなことが書いてありましたので、そちらのiPhone で https://developer.mozilla.org/ja/docs/Web/API/Geolocation/Using_geolocation を表示して、上記の「Show my location」ボタンをクリックしてみると、いかがでしょうか?
退会済みユーザー

退会済みユーザー

2019/11/03 15:34 編集

PCの翻訳がかかっていたので、それを原文になおしたら位置情報は取得できました! しかし、位置情報が相変わらず大きく外れていますね…。
退会済みユーザー

退会済みユーザー

2019/11/03 15:33 編集

iPhoneでは正常に位置情報を取得できました!
jun68ykt

2019/11/03 15:43

おお、そうですか! MacBook のほうで位置情報が正確ではない点については、以下などを参考にするとよいかもしれません。 OS X と Safari の位置情報サービスについて https://support.apple.com/ja-jp/HT5403 または、「macbook OS X 位置情報」でググっても分かり易く説明している記事がみつかると思います。 iPhone で 先のMDN のサイトに対しては、正常に位置情報を取得、送信できることが分かったのですが、そのiPhone でご質問にあるコンポーネントがreder される画面を表示することは(WIFI経由だったりで)できるのでしょうか?
退会済みユーザー

退会済みユーザー

2019/11/03 15:51 編集

これは一つ前の質問にも関係してくるのですが、iPhoneでlocalhostに繋ぐと、ブラウザ内で完結している動きに関しては問題なく表示、動作するのですが、バックのLaravel APIに非同期通信したり、位置情報を取得したりなどすると正常に動作しないです…。 本当に困っているので、解決方法がお分かりででしたら、本当に助かります…。
jun68ykt

2019/11/03 16:01

MacBook による開発中は、一台のMacBook の中でLaravelによるサーバーを動かし、フロントエンドは webpack dev server か何かを動かして、PC のブラウザから http://localshost:3000 のようなURLでフロント画面が表示される、的な感じを想像していますが、実際のiPhone 端末からフロント画面を表示させようとするならば、MakBook と iPhone とが同じWiFi に接続している前提で、MacBook の IP アドレスを調べて、たとえばそれば 192.168.1.100 だったとすると、iPhone のブラウザで、http://192.168.1.100:3000  というURLでアクセスしないと、iPhoneでは表示できないですね。 iPhone のブラウザで htt://localhost・・・ と打っても、 iPhone にとってのlocalhost とはそのiPhone 自身ですので。
退会済みユーザー

退会済みユーザー

2019/11/03 16:08 編集

すいません!質問に語弊がありました! localhostではなく、ipアドレスとポート番号を正確に打って、画面は表示できているのですが、ログイン処理でのLaravel APIとの通信や、現在地の取得などの通信が発生するとうまく動作しないです…。 ボタンをタップしての画面遷移や、ダイアログの表示などはできています! 開発環境に関してはLaradockを使用しています。
jun68ykt

2019/11/03 16:24

なるほど。了解です。 (1) Laravel APIとの通信については、iPhoneの実機でテストをするときは、フロントエンド側のどこかに書いてある、APIサーバーのURLも 127.0.0.1 だったり、localhost ではなく、192.168・・・か何かのIPアドレス:Laravelサーバのポートにしなければなりませんが、そのようになってますでしょうか? (2) 現在地の取得については、 navigator.geolocation.getCurrentPosition(pos => { this.setState({ lat: pos.coords.latitude, lng: pos.coords.longitude }) の this.setState は行われているということでよいのでしょうか? navigator.geolocation.getCurrentPosition は以下のような引数 navigator.geolocation.getCurrentPosition(success[, error[, [options]]) を取れるので、this.setStateが実行されているということは、 successハンドラが実行されているということなのでgetCurrentPosition が成功したことになります。 もしかすると、iPhone実機 での疎通ができると、「安全なコンテキスト (HTTPS) でのみ利用できます。」と書いてあることに反して、正確な緯度経度が表示されるかもしれませんね。(淡い願望に過ぎませんが)
jun68ykt

2019/11/03 16:31

何にせよ、この先開発を進めるにあたって、まずは、お手持ちの iPhoneの実機と、MacBook上のフロントエンドdevサーバー、バックエンドAPIサーバー(Laravel)とを疎通させて、iPhone 上でも動作確認できるところまでもっていくことが優先順位高そうな気がします。(もちろん、ふだんの開発は localhost で PCのブラウザからでよいと思いますが。)
退会済みユーザー

退会済みユーザー

2019/11/03 16:43

何度も丁寧なご回答ありがとうございます! 携帯の方でのLaravel APIとの通信はipアドレスを変更したら通信できました! localhostにしていました!申し訳ございません! 位置情報の取得に関しては相変わらずですね…。 successハンドラ内でconsole.logを随所でしたところすべて表示されているので、恐らく取得はできているのかもしれません。
退会済みユーザー

退会済みユーザー

2019/11/03 16:45 編集

位置情報の取得は上記に載せている通り、componentDidMount内で実行しています。それをstateに保存しています。
退会済みユーザー

退会済みユーザー

2019/11/03 16:45

それを、render()内のGoogle Mapで使用していると言う感じですね。
jun68ykt

2019/11/03 17:00 編集

なるほどですね。 ちょっと余談ですが navigator.geolocation.getCurrentPosition の第1引数は成功時のコールバックですが、第2引数のコーバックは、失敗時のもので、以下に書き方の例がありました。 https://stackoverflow.com/a/39367531 上記の var browserGeolocationFail = function(error) { ・・・ }  です。いくつかの case があるようです。 ただ、khkhkhさんの現状では、成功時のコールバックに行っているわけですよね? 調べが足りないと思うのは、https ではなく http でアクセスした場合に、getCurrentPosition がどの程度、うまくいかないのかは、ブラウザ依存だったりプラットフォーム依存(PC or iOS or Android )だったりするのでは? ということです。ブラウザによっては、失敗ではなく成功コールバックに一応いくのだけれども、位置情報はそんなに正確には出ない、みたいな挙動をするのかもしれません。(←思いつきを言ってます。)このあたりを掘っていってもいいですが、やはりMDNに この機能は一部またはすべての対応しているブラウザーにおいて、安全なコンテキスト (HTTPS) でのみ利用できます。 と一番上に明記されているわけですから、(失敗の仕方がブラウザによってまちまちであるのかもしれないけれども、何にせよ)上手くいかないのが想定内という気はします。
jun68ykt

2019/11/03 17:04

ところで、 > 携帯の方でのLaravel APIとの通信はipアドレスを変更したら通信できました! とのことだったので、そうすると、ひとつ前のご質問 React+Redux+Material-ui onClickイベントがiOSで反応しない は解決されたのでしょうか?(ひとつでも問題が解決できたらいいなと思う次第です)
退会済みユーザー

退会済みユーザー

2019/11/03 17:05

なるほど…。確かに納得いたしました! 私の調べが足りてませんでしたね…。 jun68yktさんの回答で全ての疑問が解消されました! 最後まで拙い質問に付き合って頂き本当にありがとうございます!! またご縁があれば是非回答をよろしくお願いいたします!!!
退会済みユーザー

退会済みユーザー

2019/11/03 17:07 編集

あ、それらも無事解決致しました!感謝感激です!ありがとうございました!!
jun68ykt

2019/11/03 17:09

どういたしまして! それでは、 React+Redux+Material-ui onClickイベントがiOSで反応しない は自己解決にされるとよいでしょう。 また次回お役に立てれば幸いです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問