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
2 Answers
Reset to default 4Apparently 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.