From ad56dd63d16ddb90b08c172f8156dd83f3d1e575 Mon Sep 17 00:00:00 2001 From: Tobias Date: Thu, 19 Dec 2024 08:30:36 +0100 Subject: [PATCH] Improve docs and hooks-example for `useMap` and `MapProvider` (#2118) --- docs/api-reference/map.md | 18 ++++++--------- docs/api-reference/use-map.md | 10 ++++++--- examples/get-started/hook/app.jsx | 2 ++ examples/get-started/hook/controls.jsx | 30 +++++++++++++++++++++---- examples/get-started/hook/controls2.jsx | 24 ++++++++++++++++++++ examples/get-started/hook/map.jsx | 27 ++++++++++++++++++++-- 6 files changed, 91 insertions(+), 20 deletions(-) create mode 100644 examples/get-started/hook/controls2.jsx diff --git a/docs/api-reference/map.md b/docs/api-reference/map.md index bbd99c477..01535d680 100644 --- a/docs/api-reference/map.md +++ b/docs/api-reference/map.md @@ -53,7 +53,6 @@ function App() { - ## Properties Aside from the props listed below, the `Map` component supports all parameters of the `Map` class constructor ([Mapbox](https://docs.mapbox.com/mapbox-gl-js/api/map/) | [Maplibre](https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/MapOptions/)). Beware that this is not an exhaustive list of all props. Different base map libraries may offer different options and default values. When in doubt, refer to your base map library's documentation. @@ -64,6 +63,10 @@ Aside from the props listed below, the `Map` component supports all parameters o Map container id. +Required when [`MapProvider`](./map-provider.md)s are used. Used to reference the map with [`useMap`](./use-map.md). + +Make sure to pick a name that has no conflict with other imports (there are no checks or errors in this case). + #### `style`: CSSProperties {#style} Default: `{position: 'relative', width: '100%', height: '100%'}` @@ -116,7 +119,6 @@ Enable diffing when `mapStyle` changes. If `false`, force a 'full' update, remov Terrain property of the style. Must conform to the [Terrain Style Specification](https://docs.mapbox.com/mapbox-gl-js/style-spec/terrain/). If `undefined` is provided, removes terrain from the map. - ### Camera options #### `initialViewState`: object {#initialviewstate} @@ -461,13 +463,14 @@ Called when one of the map's sources loads or changes, including if a tile belon ### Other options -The following props, along with any options of the `Map` class ([Mapbox](https://docs.mapbox.com/mapbox-gl-js/api/map/) | [Maplibre](https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/MapOptions/)) not listed above, can be specified to construct the underlying `Map` instance. +The following props, along with any options of the `Map` class ([Mapbox](https://docs.mapbox.com/mapbox-gl-js/api/map/) | [Maplibre](https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/MapOptions/)) not listed above, can be specified to construct the underlying `Map` instance. Note: props in this section are not reactive. They are only used once when the Map instance is constructed. #### `mapLib`: any {#maplib} Default: + - `import('mapbox-gl')` if imported from `react-map-gl` - `import('maplibre-gl')` if imported from `react-map-gl/maplibre` @@ -499,7 +502,7 @@ function App() { Or to load a pre-bundled version of the library: ```html title="index.html" - + ``` ```tsx title="app.tsx" @@ -511,7 +514,6 @@ function App() { } ``` - #### `mapboxAccessToken`: string {#mapboxaccesstoken} Token used to access the Mapbox data service. See [about map tokens](../get-started/mapbox-tokens.md). @@ -561,8 +563,6 @@ The number of web workers instantiated on a page with mapbox-gl maps. Provides an interface for loading mapbox-gl's WebWorker bundle from a self-hosted URL. This is useful if your site needs to operate in a strict CSP (Content Security Policy) environment wherein you are not allowed to load JavaScript code from a Blob URL, which is default behavior. - - ## Methods Imperative methods are accessible via a [React ref](https://reactjs.org/docs/refs-and-the-dom.html#creating-refs) or the [useMap](./use-map.md) hook. @@ -592,7 +592,6 @@ function App() { - ```tsx import * as React from 'react'; import {useRef, useCallback} from 'react'; @@ -612,7 +611,6 @@ function App() { } ``` - @@ -624,8 +622,6 @@ You can still access the hidden members via `getMap()`: Returns the native `Map` ([Mapbox](https://docs.mapbox.com/mapbox-gl-js/api/map/) | [Maplibre](https://maplibre.org/maplibre-gl-js/docs/API/classes/Map/)) instance associated with this component. - - ## Source [map.tsx](https://github.com/visgl/react-map-gl/tree/7.0-release/src/components/map.tsx) diff --git a/docs/api-reference/use-map.md b/docs/api-reference/use-map.md index 26fc19b40..319deacae 100644 --- a/docs/api-reference/use-map.md +++ b/docs/api-reference/use-map.md @@ -1,6 +1,8 @@ # useMap -The `useMap` hook allows a custom component to reference the [Map](./map.md) that contains it. +The `useMap` hook allows a component to reference the [Map](./map.md) that contains it. + +When used with [MapProvider](./map-provider.md), this hook can also reference maps that are rendered outside of the current map component's direct render tree. import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; @@ -60,7 +62,7 @@ function NavigateButton() { -When used with the [MapProvider](./map-provider.md), this hook can also reference maps that are rendered outside of the current component's direct render tree. +When used with the [MapProvider](./map-provider.md), this hook can also reference maps that are rendered outside of the current component's direct render tree as long as both trees are part of the current ``. @@ -70,6 +72,8 @@ When used with the [MapProvider](./map-provider.md), this hook can also referenc import {MapProvider, Map, useMap} from 'react-map-gl'; function Root() { + // Note: `useMap` will not work in , only children of can use `useMap` + return ( @@ -131,7 +135,7 @@ See a full example [here](https://github.com/visgl/react-map-gl/tree/7.0-release The hook returns an object that contains all mounted maps under the closest `MapProvider`. The keys are each map's [id](./map.md#id) and the values are the [MapRef](./types.md#mapref). -If the hook is used inside a decendent of a `Map` component, the returned object also contains a `current` field that references the containing map. +If the hook is used inside a decendent of a `Map` component, the returned object additionally contains a `current` field that references the containing map. ## Source diff --git a/examples/get-started/hook/app.jsx b/examples/get-started/hook/app.jsx index f1ae16715..66425cc73 100644 --- a/examples/get-started/hook/app.jsx +++ b/examples/get-started/hook/app.jsx @@ -7,6 +7,8 @@ import Map from './map'; import Controls from './controls'; function Root() { + // Note: `useMap` will not work here, only child components of `MapProvider` or `Map` can use `useMap` + return ( diff --git a/examples/get-started/hook/controls.jsx b/examples/get-started/hook/controls.jsx index 06cea0011..c1e23baef 100644 --- a/examples/get-started/hook/controls.jsx +++ b/examples/get-started/hook/controls.jsx @@ -4,14 +4,34 @@ import {useCallback, useState, useEffect} from 'react'; import {useMap} from 'react-map-gl'; export default function Controls() { - const {mymap} = useMap(); + /** + * ## This is how `useMap` works: + * ``` + * const maps = useMap(); + * console.log('Controls useMap()', maps); + * ``` + * ### First render: + * ``` + * { + * "current": undefined + * } + * ``` + * ### Second render: + * ``` + * { + * "current": undefined, + * "mymap": {...} // See https://visgl.github.io/react-map-gl/docs/api-reference/types#mapref + * } + * ``` + */ + + const {mymap} = useMap(); // `mymap` is the id in + const [inputValue, setInputValue] = useState(''); const [hasError, setError] = useState(false); useEffect(() => { - if (!mymap) { - return undefined; - } + if (!mymap) return undefined; const onMove = () => { const {lng, lat} = mymap.getCenter(); @@ -31,6 +51,8 @@ export default function Controls() { }, []); const onSubmit = useCallback(() => { + if (!mymap) return; + const [lng, lat] = inputValue.split(',').map(Number); if (Math.abs(lng) <= 180 && Math.abs(lat) <= 85) { mymap.easeTo({ diff --git a/examples/get-started/hook/controls2.jsx b/examples/get-started/hook/controls2.jsx new file mode 100644 index 000000000..139ac5a35 --- /dev/null +++ b/examples/get-started/hook/controls2.jsx @@ -0,0 +1,24 @@ +// import {useMap} from 'react-map-gl'; + +export default function Controls2() { + /** + * ## This is how `useMap` works: + * This component does nothing. It's purpose is to demo `useMap`. + * When a component is a child of ``, `useMap` has a `current` field that references the containing map. + * See https://visgl.github.io/react-map-gl/docs/api-reference/use-map + * See https://visgl.github.io/react-map-gl/docs/api-reference/types#mapref + * ``` + * const maps = useMap(); + * console.log('Controls2 useMap()', maps); + * ``` + * ### First render: + * ``` + * { + * "current": {...}, // this is the same as `mymap` + * "mymap": {...} + * } + * ``` + */ + + return null; +} diff --git a/examples/get-started/hook/map.jsx b/examples/get-started/hook/map.jsx index f7c0e222f..dad4e6cd7 100644 --- a/examples/get-started/hook/map.jsx +++ b/examples/get-started/hook/map.jsx @@ -1,14 +1,35 @@ import * as React from 'react'; import Map from 'react-map-gl'; +// import {useMap} from 'react-map-gl'; import 'mapbox-gl/dist/mapbox-gl.css'; +import Controls2 from './controls2'; const MAPBOX_TOKEN = ''; // Set your mapbox token here export default function MapView() { + /** + * ## This is how `useMap` works: + * ``` + * const maps = useMap(); + * console.log('MapView useMap()', maps); + * ``` + * ### First render: + * ``` + * { + * "current": undefined + * } + * Second render: + * { + * "current": undefined, + * "mymap": {...} // See https://visgl.github.io/react-map-gl/docs/api-reference/types#mapref + * } + * ``` + */ + return ( + > + + ); }