最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to change google map language after first react render? - Stack Overflow

programmeradmin3浏览0评论

I use . I need to change my map language by click to button. I can change it only once, for example from ja to ar, but can't back to ja. How can I do that?

<MyMapComponent
   key={language}
   googleMapURL={`=${key}&language=${this.props.language}`}
   isMarkerShown
   containerElement={
     <div style={{ height: '100%' }} />
   }
   mapElement={
     <div style={{ height: '100%' }} />
   }
   loadingElement={
     <div style={{ height: '100%' }} />
   }
/>

Here is example without react /

PS sorry for my english

I use https://github./tomchentw/react-google-maps. I need to change my map language by click to button. I can change it only once, for example from ja to ar, but can't back to ja. How can I do that?

<MyMapComponent
   key={language}
   googleMapURL={`https://maps.googleapis./maps/api/js?key=${key}&language=${this.props.language}`}
   isMarkerShown
   containerElement={
     <div style={{ height: '100%' }} />
   }
   mapElement={
     <div style={{ height: '100%' }} />
   }
   loadingElement={
     <div style={{ height: '100%' }} />
   }
/>

Here is example without react http://jsfiddle/2AKqM/

PS sorry for my english

Share Improve this question edited Dec 14, 2017 at 7:00 Rabinzon asked Dec 14, 2017 at 6:45 RabinzonRabinzon 111 silver badge2 bronze badges 2
  • It seems working properly in your jsfiddle. – Madhavan.V Commented Dec 14, 2017 at 6:48
  • @Madhavan.V yep, but I need to use react-google-maps. When I pass new map url, map refreshing but not change language – Rabinzon Commented Dec 14, 2017 at 7:00
Add a ment  | 

2 Answers 2

Reset to default 4

Apparently it occurs due to a conflict while loading Google Maps API more then once on the page. You've probably using withScriptjs for loading Google Maps API, something like this:

export const MyMapComponent = pose(
  withScriptjs,
  withGoogleMap
)(props => {
  return (
    <GoogleMap googleMapURL={props.googleMapsUrl} defaultZoom={8} defaultCenter={{ lat: -34.397, lng: 150.644 }}>
      <Marker position={{ lat: -34.397, lng: 150.644 }} />
    </GoogleMap>
  )
});

The point is, that once the language is provided, the ponent is getting re-created which in turn causes to load Google Maps API again. That scenario is not supported and the following error ussually is getting displayed in console:

You have included the Google Maps API multiple times on this page. This may cause unexpected errors.

To prevent such kind of conflicts, the Google Maps API could be cleared

window.google.maps = {}; 

before the loading of API for another language.

The below example demonstrates how to handle this scenario, in particular:

  • loaded Google Maps API for a current language is stored into a cache
  • if Google Maps API has already been loaded per a selected language, it is getting re-stored from a cache, otherwise the API is cleared and loaded again

Example:

/*global google*/
import React from "react";
import { pose, withProps } from "repose";
import {
  withScriptjs,
  withGoogleMap,
  GoogleMap,
  Marker
} from "react-google-maps";


const key = "AIzaSyDurZQBXjtSzKeieXwtFeGe-jhZu-HEGQU";

export const MyMapComponent = pose(
  withScriptjs,
  withGoogleMap
)(props => {
  return (
    <GoogleMap googleMapURL={props.googleMapsUrl} defaultZoom={8} defaultCenter={{ lat: -34.397, lng: 150.644 }}>
      <Marker position={{ lat: -34.397, lng: 150.644 }} />
    </GoogleMap>
  )
});


export default class App extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      language: 'en',
      nextLanguage: null,
      googleMapsUrl: `https://maps.googleapis./maps/api/js?key=${key}&language=en`,
      cacheMaps: {}
    };
  }

  handleChange(e) {
    this.setState({ nextLanguage: e.target.value });
  }

  changeGoogleMapsLanguage = () => {
    this.setState({ googleMapsUrl: `https://maps.googleapis./maps/api/js?key=${key}&language=${this.state.nextLanguage}` });
    this.setState({ language: this.state.nextLanguage });

    let cacheMaps = { ...this.state.cacheMaps }
    cacheMaps[this.state.language] = window.google.maps;
    this.setState({ cacheMaps });

    if (this.state.nextLanguage in cacheMaps) {
      window.google.maps = cacheMaps[this.state.nextLanguage];  //load Maps API from cache
      console.log("Loading from cache..");
    }
    else {
      window.google.maps = {}; //clear Maps ponents 
    }

  }



  render() {
    return (
      <div>
        <input type="text" id="language" defaultValue={this.state.language} onChange={this.handleChange.bind(this)} />
        <button id="localization-button" onClick={this.changeGoogleMapsLanguage.bind(this)} >Change Language</button>
        <MyMapComponent googleMapURL={this.state.googleMapsUrl}
          loadingElement={<div style={{ height: `100%` }} />}
          containerElement={<div style={{ height: `400px` }} />}
          mapElement={<div style={{ height: `100%` }} />}
          key={this.state.googleMapsUrl}
        />
      </div>
    )
  }
}

I've just created a react hook which is called gmaps-script-loader. You can use it as follow:

App.tsx

import { useEffect, useRef, useState } from 'react';
import { useScriptLoader } from 'gmaps-script-loader';
import Language from './Language';
import './styles.css';

export default function App() {
  const ref = useRef<HTMLDivElement | null>(null);

  const { loadScript, isMapReady, isReloadOk } = useScriptLoader({
    apiKey: process.env.REACT_APP_GOOGLE_MAPS_API_KEY as string,
    libraries: ['places'],
  });

  const [language, setLanguage] = useState<string>('bahasa');

  useEffect(() => {
    loadScript('id', 'ID');
  }, [loadScript]);

  useEffect(() => {
    if (ref.current && isMapReady) {
      console.log('map init');
      new google.maps.Map(ref.current, {
        zoom: 12,
        center: { lat: -6.21462, lng: 106.84513 },
      });
    }
  }, [isMapReady]);

  return (
    <>
      {isReloadOk && (
        <Language
          loadScript={loadScript}
          language={language}
          setLanguage={setLanguage}
        />
      )}
      <div ref={ref} style={{ width: '100%', height: '100vh' }} />
    </>
  );
}

And the language selector Language.tsx

import { Dispatch, SetStateAction, useEffect } from 'react';

type Lang = { language: string; region: string };

interface Languages {
  [key: string]: Lang;
}

const languages: Languages = {
  bahasa: {
    language: 'id',
    region: 'ID',
  },
  english: {
    language: 'en',
    region: 'GB',
  },
  chinese: {
    language: 'zh',
    region: 'CN',
  },
};

const options = ['bahasa', 'english', 'chinese'];

export default function Language({
  loadScript,
  language,
  setLanguage,
}: {
  loadScript: (language: string, region: string) => void;
  language: string;
  setLanguage: Dispatch<SetStateAction<string>>;
}) {
  useEffect(() => {
    if (language) {
      const selected = languages[language];
      loadScript(selected.language, selected.region);
    }
  }, [language, loadScript]);

  return (
    <div style={{ position: 'absolute', right: 70, top: 10, zIndex: 50 }}>
      <select value={language} onChange={e => setLanguage(e.target.value)}>
        {options.map(opt => (
          <option value={opt} key={opt}>
            {opt.charAt(0).toUpperCase() + opt.slice(1)}
          </option>
        ))}
      </select>
    </div>
  );
}

You can check the demo here and if the API_KEY has expired, you can fork the sandbox and replace REACT_APP_GOOGLE_MAPS_API_KEY at .env file with yours.

发布评论

评论列表(0)

  1. 暂无评论