Skip to content

Instantly share code, notes, and snippets.

@tomasznguyen
Last active June 15, 2022 03:25
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save tomasznguyen/ac28b0b3207c08a81687b657a2ce86d6 to your computer and use it in GitHub Desktop.
Save tomasznguyen/ac28b0b3207c08a81687b657a2ce86d6 to your computer and use it in GitHub Desktop.
When adding Google Maps to your react application using the library @react-google-maps/api, you run into issues when having multiple components loading a map. In this gist you'll find a component and a hook to resolve these issues and to simplify integrating the library in your application.
import React, { FC } from 'react';
import { GoogleMap } from '@react-google-maps/api';
import { useGoogleMaps } from './GoogleMapsProvider';
const containerStyle = {
width: '400px',
height: '400px'
};
const center = {
lat: -3.745,
lng: -38.523
};
const App: FC = () => {
const { isLoaded } = useGoogleMaps();
return isLoaded
? (
<GoogleMap
mapContainerStyle={containerStyle}
center={center}
zoom={10}
/>
)
: (
<div>Loading...</div>
);
};
import React, { createContext, FC, useContext } from 'react';
import { useJsApiLoader } from '@react-google-maps/api';
import { UseLoadScriptOptions } from '@react-google-maps/api/dist/useJsApiLoader';
export type GoogleMapsState = {
isLoaded: boolean;
loadError?: Error;
};
const GoogleMapsContext = createContext<GoogleMapsState>({ isLoaded: false });
export const GoogleMapsProvider: FC<UseLoadScriptOptions> = ({ children, ...loadScriptOptions }) => {
const { isLoaded, loadError } = useJsApiLoader(loadScriptOptions);
return (
<GoogleMapsContext.Provider value={{ isLoaded, loadError }}>
{children}
</GoogleMapsContext.Provider>
);
};
export const useGoogleMaps = () => useContext(GoogleMapsContext);
import { Libraries } from "@react-google-maps/api/dist/utils/make-load-script-url";
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { BrowserRouter as Router } from "react-router-dom";
import App from 'app';
import store from 'state/store';
import { GoogleMapsProvider } from './GoogleMapsProvider';
const googleMapsApiKey = 'abracadabra';
const googleMapsLibraries: Libraries = [ 'places' ];
ReactDOM.render(
<React.StrictMode>
<Router>
<Provider store={store}>
<GoogleMapsProvider googleMapsApiKey={googleMapsApiKey} language="en" libraries={googleMapsLibraries}>
<App />
</GoogleMapsProvider>
</Provider>
</Router>
</React.StrictMode>,
document.getElementById('root')
);
@JustFly1984
Copy link

You need to cache value to useMemo before passing it to GoogleMapsContext.Provider to reduce re-rendering and fix performance.

@tomasznguyen
Copy link
Author

@JustFly1984 Thank you for having a look and your feedback. I tried your suggestion by caching the value, however, I don't see a difference in the amounts of re-rendering when using caching vs not using caching (see https://codesandbox.io/s/optimistic-napier-l34tu). I believe that the values are already cached inside useJsApiLoader. The provider is rendered at most twice which makes sense: once when the scripts are not loaded yet and then another time when the scripts are loaded. Can you help me understand where and/or how I should correctly implement caching?

@alexandermckay
Copy link

Fantastic. Thank you!

@Maik3345
Copy link

Nice code, Thank you!!

@aludvigsen
Copy link

Nice 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment