Skip to content

Commit a404662

Browse files
authored
docs: add documentation on migrating from @googlemaps/react-wrapper (#612)
Add a small example and documentation on how to migrate code written with the @googlemaps/react-wrapper library to @vis.gl/react-google-maps.
1 parent a5b0359 commit a404662

File tree

8 files changed

+275
-1
lines changed

8 files changed

+275
-1
lines changed
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# Migrating from `@googlemaps/react-wrapper`
2+
3+
The [`@googlemaps/react-wrapper`][npm-react-wrapper] library provides a
4+
minimal wrapper for loading the Maps JavaScript API in a React Application.
5+
6+
If you decide to migrate from using `@googlemaps/react-wrapper` to this
7+
library, this can be done seamlessly by using a poyfill for the `<Wrapper>`
8+
component.
9+
10+
Roughly speaking, our [`<APIProvider>`][rgm-api-provider] component has the
11+
same function as the `<Wrapper>` component provided by
12+
`@googlemaps/react-wrapper`, with one major difference: While the `Wrapper`
13+
component will only render its children once the Google Maps JavaScript API
14+
has been loaded, the `APIProvider` will always render the children and use
15+
custom hooks like [`useApiLoadingStatus()`][rgm-use-api-loading-status] to
16+
handle API loading in its components.
17+
18+
The following code shows how the `Wrapper` component can be implemented with
19+
this library in a fully compatible way, allowing you to use it as a
20+
drop-in-replacement for the `@googlemaps/react-wrapper` library.
21+
22+
[A complete example can be found here][rgm-examples-react-wrapper-migration].
23+
24+
```tsx title="wrapper.tsx"
25+
import React, {
26+
FunctionComponent,
27+
PropsWithChildren,
28+
ReactNode,
29+
useEffect
30+
} from 'react';
31+
32+
import {
33+
APILoadingStatus,
34+
APIProvider,
35+
APIProviderProps,
36+
useApiLoadingStatus
37+
} from '@vis.gl/react-google-maps';
38+
39+
const STATUS_MAP = {
40+
[APILoadingStatus.LOADING]: 'LOADING',
41+
[APILoadingStatus.LOADED]: 'SUCCESS',
42+
[APILoadingStatus.FAILED]: 'FAILURE'
43+
} as const;
44+
45+
type WrapperProps = PropsWithChildren<
46+
{
47+
apiKey: string;
48+
callback?: (status: string) => void;
49+
render?: (status: string) => ReactNode;
50+
} & APIProviderProps
51+
>;
52+
53+
export const Wrapper: FunctionComponent<WrapperProps> = ({
54+
apiKey,
55+
children,
56+
render,
57+
callback,
58+
...apiProps
59+
}) => {
60+
return (
61+
<APIProvider apiKey={apiKey} {...apiProps}>
62+
<InnerWrapper render={render}>{children}</InnerWrapper>
63+
</APIProvider>
64+
);
65+
};
66+
67+
const InnerWrapper = ({
68+
callback,
69+
render,
70+
children
71+
}: PropsWithChildren<Omit<WrapperProps, 'apiKey'>>) => {
72+
const status = useApiLoadingStatus();
73+
const mappedStatus = STATUS_MAP[status] ?? 'LOADING';
74+
75+
useEffect(() => {
76+
if (callback) callback(mappedStatus);
77+
}, [callback, mappedStatus]);
78+
79+
if (status === APILoadingStatus.LOADED) return children;
80+
if (render) return render(mappedStatus);
81+
82+
return <></>;
83+
};
84+
```
85+
86+
[npm-react-wrapper]: https://www.npmjs.com/package/@googlemaps/react-wrapper
87+
[rgm-api-provider]: ../api-reference/components/api-provider.md
88+
[rgm-use-api-loading-status]: ../api-reference/hooks/use-api-loading-status.md
89+
[rgm-examples-react-wrapper-migration]: https://github.com/visgl/react-google-maps/tree/main/examples/react-wrapper-migration

docs/table-of-contents.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
"guides/interacting-with-google-maps-api",
1818
"guides/deckgl-integration",
1919
"guides/ssr-and-frameworks",
20-
"guides/writing-examples"
20+
"guides/writing-examples",
21+
"guides/migrating-from-react-wrapper"
2122
]
2223
},
2324
{
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Migrating from @googlemaps/react-wrapper
2+
3+
This is an example to show how code that was written using
4+
`@googlemaps/react-wrapper` can be ported to this library.
5+
6+
## Google Maps Platform API key
7+
8+
This example does not come with an API key. Running the examples locally requires a valid API key for the Google Maps Platform.
9+
See [the official documentation][get-api-key] on how to create and configure your own key.
10+
11+
The API key has to be provided via an environment variable `GOOGLE_MAPS_API_KEY`. This can be done by creating a
12+
file named `.env` in the example directory with the following content:
13+
14+
```shell title=".env"
15+
GOOGLE_MAPS_API_KEY="<YOUR API KEY HERE>"
16+
```
17+
18+
If you are on the CodeSandbox playground you can also choose to [provide the API key like this](https://codesandbox.io/docs/learn/environment/secrets)
19+
20+
## Development
21+
22+
Go into the example-directory and run
23+
24+
```shell
25+
npm install
26+
```
27+
28+
To start the example with the local library run
29+
30+
```shell
31+
npm run start-local
32+
```
33+
34+
The regular `npm start` task is only used for the standalone versions of the example (CodeSandbox for example)
35+
36+
[get-api-key]: https://developers.google.com/maps/documentation/javascript/get-api-key
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta
6+
name="viewport"
7+
content="width=device-width, initial-scale=1.0, user-scalable=no" />
8+
<title>Example:</title>
9+
10+
<style>
11+
body {
12+
margin: 0;
13+
font-family: sans-serif;
14+
}
15+
#app {
16+
width: 100vw;
17+
height: 100vh;
18+
}
19+
</style>
20+
</head>
21+
<body>
22+
<div id="app"></div>
23+
<script type="module">
24+
import '@vis.gl/react-google-maps/examples.css';
25+
import '@vis.gl/react-google-maps/examples.js';
26+
import {renderToDom} from './src/app';
27+
28+
renderToDom(document.querySelector('#app'));
29+
</script>
30+
</body>
31+
</html>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"type": "module",
3+
"dependencies": {
4+
"@googlemaps/react-wrapper": "^1.1.42",
5+
"@vis.gl/react-google-maps": "latest",
6+
"react": "^18.2.0",
7+
"react-dom": "^18.2.0",
8+
"vite": "^5.0.4"
9+
},
10+
"scripts": {
11+
"start": "vite",
12+
"start-local": "vite --config ../vite.config.local.js",
13+
"build": "vite build"
14+
}
15+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import React from 'react';
2+
import {createRoot} from 'react-dom/client';
3+
4+
// import {Wrapper} from '@googlemaps/react-wrapper';
5+
import {Wrapper} from './wrapper';
6+
7+
const API_KEY =
8+
// @ts-ignore
9+
globalThis.GOOGLE_MAPS_API_KEY ?? (process.env.GOOGLE_MAPS_API_KEY as string);
10+
11+
const MapsTest = () => {
12+
return <h1>Google Maps JavaScript API v{google.maps.version} Loaded.</h1>;
13+
};
14+
15+
const App = () => (
16+
<Wrapper apiKey={API_KEY} render={status => <h1>Status: {status}</h1>}>
17+
<MapsTest />
18+
</Wrapper>
19+
);
20+
21+
export default App;
22+
23+
export function renderToDom(container: HTMLElement) {
24+
const root = createRoot(container);
25+
26+
root.render(
27+
<React.StrictMode>
28+
<App />
29+
</React.StrictMode>
30+
);
31+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import React, {
2+
FunctionComponent,
3+
PropsWithChildren,
4+
ReactNode,
5+
useEffect
6+
} from 'react';
7+
import {APIProvider, useApiLoadingStatus} from '../../../src';
8+
import {APILoadingStatus, APIProviderProps} from '@vis.gl/react-google-maps';
9+
10+
const statusMap = {
11+
[APILoadingStatus.LOADING]: 'LOADING',
12+
[APILoadingStatus.LOADED]: 'SUCCESS',
13+
[APILoadingStatus.FAILED]: 'FAILURE'
14+
} as const;
15+
16+
type WrapperProps = PropsWithChildren<
17+
{
18+
apiKey: string;
19+
callback?: (status: string) => void;
20+
render?: (status: string) => ReactNode;
21+
} & APIProviderProps
22+
>;
23+
24+
export const Wrapper: FunctionComponent<WrapperProps> = ({
25+
apiKey,
26+
children,
27+
render,
28+
callback,
29+
...apiProps
30+
}) => {
31+
return (
32+
<APIProvider apiKey={apiKey} {...apiProps}>
33+
<InnerWrapper render={render}>{children}</InnerWrapper>
34+
</APIProvider>
35+
);
36+
};
37+
38+
const InnerWrapper = ({
39+
callback,
40+
render,
41+
children
42+
}: PropsWithChildren<Omit<WrapperProps, 'apiKey'>>) => {
43+
const status = useApiLoadingStatus();
44+
const mappedStatus = statusMap[status] ?? 'LOADING';
45+
46+
useEffect(() => {
47+
if (callback) callback(mappedStatus);
48+
}, [callback, mappedStatus]);
49+
50+
if (status === APILoadingStatus.LOADED) return children;
51+
if (render) return render(mappedStatus);
52+
53+
return <></>;
54+
};
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import {defineConfig, loadEnv} from 'vite';
2+
3+
export default defineConfig(({mode}) => {
4+
const {GOOGLE_MAPS_API_KEY = ''} = loadEnv(mode, process.cwd(), '');
5+
6+
return {
7+
define: {
8+
'process.env.GOOGLE_MAPS_API_KEY': JSON.stringify(GOOGLE_MAPS_API_KEY)
9+
},
10+
resolve: {
11+
alias: {
12+
'@vis.gl/react-google-maps/examples.js':
13+
'https://visgl.github.io/react-google-maps/scripts/examples.js'
14+
}
15+
}
16+
};
17+
});

0 commit comments

Comments
 (0)