web-dev-qa-db-ja.com

必要な場合にのみ、reactアプリにgoogle maps api <script>をロードするにはどうすればよいですか?

Google maps APIを使用して地図を表示したいのですが、index.htmlに入れるよりも<script>タグを読み込む方が良い方法があるのではないかと思います。

/mapルートに移動したときにのみスクリプトをロードしたいと思います。したがって、index.htmlから削除して、動的にロードしたいと思います。ただし、すでにロードされている場合は、再度ロードしないようにする必要もあります。

これを処理するライブラリがあるかどうかはわかりません。私がこれまでに試した(しかし失敗した)のは、実際のdomに<script>を追加し、それにキーを割り当てるloadScript関数を作成することです。この場合、'google-mapsです。

ありがとう

9
user1354934

2019年10月6日更新:サンプルコードは引き続き正常に機能しています。デコレータ以外の構文を使用するように更新しました。


これが私の最近のプロジェクトで機能させたものです。 react-async-script-loader コンポーネントを使用しました。

import React from 'react';
import scriptLoader from 'react-async-script-loader';

class Maps extends React.Component {
  constructor(props) {
    super(props);
    this.map = null;
  }

  componentWillReceiveProps({ isScriptLoaded, isScriptLoadSucceed }) {
    if (isScriptLoaded && !this.props.isScriptLoaded) {
      // load finished
      if (isScriptLoadSucceed) {
        this.map = new google.maps.Map(this.refs.map, {
          center: { lat: 10.794234, lng: 106.706541 },
          zoom: 20
        });

        if (navigator.geolocation) {
          navigator.geolocation.getCurrentPosition(
            position => {
              const pos = {
                lat: position.coords.latitude,
                lng: position.coords.longitude
              };

              this.map.setCenter(pos);

              const marker = new google.maps.Marker({
                position: pos,
                map: this.map,
                title: 'Hello World!'
              });
            },
            () => {
              console.log('navigator disabled');
            }
          );
        } else {
          // Browser doesn't support Geolocation
          console.log('navigator disabled');
        }
      } else this.props.onError();
    }
  }

  render() {
    return (
      <div>
        <div ref="map" style={{ height: '80%', width: '100%' }}></div>
        {!this.map && <div className="center-md">Loading...</div>}
      </div>
    );
  }
}

export default scriptLoader(['https://maps.googleapis.com/maps/api/js?key=API_KEY'])(Maps);
10
Thanh Nguyen

ありがとう グエンタンgoogleがグローバルスコープになっているので、window.googleを使用しました。

import React, { Component } from 'react';
import scriptLoader from 'react-async-script-loader';
class Map extends Component{
    constructor(props) {
        super(props);
    }
    componentWillReceiveProps({isScriptLoadSucceed}){
        if (isScriptLoadSucceed) {
            var markers = [];

            var map = new window.google.maps.Map(document.getElementById('map'), {
                zoom: 12,
                center: {lat: 37.7749300, lng: -122.4194200}
            });
        }
        else{
            alert("script not loaded")
        }
    }

    render(){
        return(
            <div>
                <div id="map" style={{height: "600px"}}></div>
            </div>
        )
    }
}

export default scriptLoader(
    ["https://maps.googleapis.com/maps/api/js?key= APIKEY"]
)(Map)

反応フックを使用すると、外部スクリプトをロードすることもできます

https://usehooks.com/useScript/

//useScript custom hooks from the site

let cachedScripts = [];

function useScript(src) {
  // Keeping track of script loaded and error state

  const [state, setState] = useState({
    loaded: false,
    error: false
  });

  useEffect(
    () => {
      // If cachedScripts array already includes src that means another instance ...
      // ... of this hook already loaded this script, so no need to load again.
      if (cachedScripts.includes(src)) {
        setState({
          loaded: true,

          error: false
        });
      } else {
        cachedScripts.Push(src);
        // Create script
        let script = document.createElement("script");
        script.src = src;
        script.async = true;
        // Script event listener callbacks for load and error
        const onScriptLoad = () => {
          setState({
            loaded: true,
            error: false
          });
        };

        const onScriptError = () => {
          // Remove from cachedScripts we can try loading again
          const index = cachedScripts.indexOf(src);
          if (index >= 0) cachedScripts.splice(index, 1);
          script.remove();
          setState({
            loaded: true,
            error: true
          });
        };
        script.addEventListener("load", onScriptLoad);
        script.addEventListener("error", onScriptError);
        // Add script to document body
        document.body.appendChild(script);
        // Remove event listeners on cleanup
        return () => {
          script.removeEventListener("load", onScriptLoad);
          script.removeEventListener("error", onScriptError);
        };
      }
    },
    [src] // Only re-run effect if script src changes
  );
  return [state.loaded, state.error];
}


使用法

//App.js
import React from "react";
import ReactDOM from "react-dom";
import { useState, useEffect } from "react";
function App() {
  const [loaded, error] = useScript(
    "https://maps.googleapis.com/maps/api/js?key=API_KEY"
  );
  useEffect(() => {
    if (loaded) {
      new window.google.maps.Map(document.getElementById("map"), {
        zoom: 12,
        center: { lat: 37.77493, lng: -122.41942 }
      });
    }
  }, [loaded]);

  return (
    <div>
      <div>
        Script loaded: <b>{loaded.toString()}</b>
      </div>
      <div id="map" style={{ height: "600px" }} />
    </div>
  );
}
6
saiful619945

さらに別のパッケージ react-dependent-script package 次の機能を提供するGoogleマップライブラリをロードします。

  • 最初にJavaScriptやCSSをロードしてから、コンテンツをレンダリングしてください
  • render()関数が呼び出された回数に関係なく、外部コンテンツが1回だけロードされるようにします

これは簡単な例で、mapコンポーネントをReactDependentScriptコンポーネントでラップします。

<ReactDependentScript
      scripts={[
        "https://maps.googleapis.com/maps/api/js?key={YOUR-KEY-GOES-HERE}"
      ]}>
      <Map center={{ lat: -34.397, lng: 150.644 }} zoom={3} />
</ReactDependentScript>

ここにデモがあります 参考のために

2