diff --git a/docs/guides/migrating-from-react-wrapper.md b/docs/guides/migrating-from-react-wrapper.md new file mode 100644 index 0000000..00534e2 --- /dev/null +++ b/docs/guides/migrating-from-react-wrapper.md @@ -0,0 +1,89 @@ +# Migrating from `@googlemaps/react-wrapper` + +The [`@googlemaps/react-wrapper`][npm-react-wrapper] library provides a +minimal wrapper for loading the Maps JavaScript API in a React Application. + +If you decide to migrate from using `@googlemaps/react-wrapper` to this +library, this can be done seamlessly by using a poyfill for the `` +component. + +Roughly speaking, our [``][rgm-api-provider] component has the +same function as the `` component provided by +`@googlemaps/react-wrapper`, with one major difference: While the `Wrapper` +component will only render its children once the Google Maps JavaScript API +has been loaded, the `APIProvider` will always render the children and use +custom hooks like [`useApiLoadingStatus()`][rgm-use-api-loading-status] to +handle API loading in its components. + +The following code shows how the `Wrapper` component can be implemented with +this library in a fully compatible way, allowing you to use it as a +drop-in-replacement for the `@googlemaps/react-wrapper` library. + +[A complete example can be found here][rgm-examples-react-wrapper-migration]. + +```tsx title="wrapper.tsx" +import React, { + FunctionComponent, + PropsWithChildren, + ReactNode, + useEffect +} from 'react'; + +import { + APILoadingStatus, + APIProvider, + APIProviderProps, + useApiLoadingStatus +} from '@vis.gl/react-google-maps'; + +const STATUS_MAP = { + [APILoadingStatus.LOADING]: 'LOADING', + [APILoadingStatus.LOADED]: 'SUCCESS', + [APILoadingStatus.FAILED]: 'FAILURE' +} as const; + +type WrapperProps = PropsWithChildren< + { + apiKey: string; + callback?: (status: string) => void; + render?: (status: string) => ReactNode; + } & APIProviderProps +>; + +export const Wrapper: FunctionComponent = ({ + apiKey, + children, + render, + callback, + ...apiProps +}) => { + return ( + + {children} + + ); +}; + +const InnerWrapper = ({ + callback, + render, + children +}: PropsWithChildren>) => { + const status = useApiLoadingStatus(); + const mappedStatus = STATUS_MAP[status] ?? 'LOADING'; + + useEffect(() => { + if (callback) callback(mappedStatus); + }, [callback, mappedStatus]); + + if (status === APILoadingStatus.LOADED) return children; + if (render) return render(mappedStatus); + + return <>; +}; +``` + +[npm-react-wrapper]: https://www.npmjs.com/package/@googlemaps/react-wrapper +[rgm-api-provider]: ../api-reference/components/api-provider.md +[rgm-use-api-loading-status]: ../api-reference/hooks/use-api-loading-status.md +[rgm-examples-react-wrapper-migration]: https://github.com/visgl/react-google-maps/tree/main/examples/react-wrapper-migration diff --git a/docs/table-of-contents.json b/docs/table-of-contents.json index dcd020e..90ca072 100644 --- a/docs/table-of-contents.json +++ b/docs/table-of-contents.json @@ -17,7 +17,8 @@ "guides/interacting-with-google-maps-api", "guides/deckgl-integration", "guides/ssr-and-frameworks", - "guides/writing-examples" + "guides/writing-examples", + "guides/migrating-from-react-wrapper" ] }, { diff --git a/examples/react-wrapper-migration/README.md b/examples/react-wrapper-migration/README.md new file mode 100644 index 0000000..63f87af --- /dev/null +++ b/examples/react-wrapper-migration/README.md @@ -0,0 +1,36 @@ +# Migrating from @googlemaps/react-wrapper + +This is an example to show how code that was written using +`@googlemaps/react-wrapper` can be ported to this library. + +## Google Maps Platform API key + +This example does not come with an API key. Running the examples locally requires a valid API key for the Google Maps Platform. +See [the official documentation][get-api-key] on how to create and configure your own key. + +The API key has to be provided via an environment variable `GOOGLE_MAPS_API_KEY`. This can be done by creating a +file named `.env` in the example directory with the following content: + +```shell title=".env" +GOOGLE_MAPS_API_KEY="" +``` + +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) + +## Development + +Go into the example-directory and run + +```shell +npm install +``` + +To start the example with the local library run + +```shell +npm run start-local +``` + +The regular `npm start` task is only used for the standalone versions of the example (CodeSandbox for example) + +[get-api-key]: https://developers.google.com/maps/documentation/javascript/get-api-key diff --git a/examples/react-wrapper-migration/index.html b/examples/react-wrapper-migration/index.html new file mode 100644 index 0000000..7dba140 --- /dev/null +++ b/examples/react-wrapper-migration/index.html @@ -0,0 +1,31 @@ + + + + + + Example: + + + + +
+ + + diff --git a/examples/react-wrapper-migration/package.json b/examples/react-wrapper-migration/package.json new file mode 100644 index 0000000..d9238b6 --- /dev/null +++ b/examples/react-wrapper-migration/package.json @@ -0,0 +1,15 @@ +{ + "type": "module", + "dependencies": { + "@googlemaps/react-wrapper": "^1.1.42", + "@vis.gl/react-google-maps": "latest", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "vite": "^5.0.4" + }, + "scripts": { + "start": "vite", + "start-local": "vite --config ../vite.config.local.js", + "build": "vite build" + } +} diff --git a/examples/react-wrapper-migration/src/app.tsx b/examples/react-wrapper-migration/src/app.tsx new file mode 100644 index 0000000..0f39d98 --- /dev/null +++ b/examples/react-wrapper-migration/src/app.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +import {createRoot} from 'react-dom/client'; + +// import {Wrapper} from '@googlemaps/react-wrapper'; +import {Wrapper} from './wrapper'; + +const API_KEY = + // @ts-ignore + globalThis.GOOGLE_MAPS_API_KEY ?? (process.env.GOOGLE_MAPS_API_KEY as string); + +const MapsTest = () => { + return

Google Maps JavaScript API v{google.maps.version} Loaded.

; +}; + +const App = () => ( +

Status: {status}

}> + +
+); + +export default App; + +export function renderToDom(container: HTMLElement) { + const root = createRoot(container); + + root.render( + + + + ); +} diff --git a/examples/react-wrapper-migration/src/wrapper.tsx b/examples/react-wrapper-migration/src/wrapper.tsx new file mode 100644 index 0000000..66561ae --- /dev/null +++ b/examples/react-wrapper-migration/src/wrapper.tsx @@ -0,0 +1,54 @@ +import React, { + FunctionComponent, + PropsWithChildren, + ReactNode, + useEffect +} from 'react'; +import {APIProvider, useApiLoadingStatus} from '../../../src'; +import {APILoadingStatus, APIProviderProps} from '@vis.gl/react-google-maps'; + +const statusMap = { + [APILoadingStatus.LOADING]: 'LOADING', + [APILoadingStatus.LOADED]: 'SUCCESS', + [APILoadingStatus.FAILED]: 'FAILURE' +} as const; + +type WrapperProps = PropsWithChildren< + { + apiKey: string; + callback?: (status: string) => void; + render?: (status: string) => ReactNode; + } & APIProviderProps +>; + +export const Wrapper: FunctionComponent = ({ + apiKey, + children, + render, + callback, + ...apiProps +}) => { + return ( + + {children} + + ); +}; + +const InnerWrapper = ({ + callback, + render, + children +}: PropsWithChildren>) => { + const status = useApiLoadingStatus(); + const mappedStatus = statusMap[status] ?? 'LOADING'; + + useEffect(() => { + if (callback) callback(mappedStatus); + }, [callback, mappedStatus]); + + if (status === APILoadingStatus.LOADED) return children; + if (render) return render(mappedStatus); + + return <>; +}; diff --git a/examples/react-wrapper-migration/vite.config.js b/examples/react-wrapper-migration/vite.config.js new file mode 100644 index 0000000..522c6cb --- /dev/null +++ b/examples/react-wrapper-migration/vite.config.js @@ -0,0 +1,17 @@ +import {defineConfig, loadEnv} from 'vite'; + +export default defineConfig(({mode}) => { + const {GOOGLE_MAPS_API_KEY = ''} = loadEnv(mode, process.cwd(), ''); + + return { + define: { + 'process.env.GOOGLE_MAPS_API_KEY': JSON.stringify(GOOGLE_MAPS_API_KEY) + }, + resolve: { + alias: { + '@vis.gl/react-google-maps/examples.js': + 'https://visgl.github.io/react-google-maps/scripts/examples.js' + } + } + }; +});