visgl / react-map-gl

React friendly API wrapper around MapboxGL JS
http://visgl.github.io/react-map-gl/
Other
7.88k stars 1.35k forks source link

[Bug] `useMap` always returns undefined #2113

Closed pReya closed 1 year ago

pReya commented 1 year ago

Description

I'm not sure whether this is a problem with mapbox-gl or react-map-gl. Anyhow, I always get undefined for useMap().current. Not sure if this is a bug, or I have a conceptual misunderstanding about how to use the hook. I basically recreated the exact example from: https://visgl.github.io/react-map-gl/docs/api-reference/use-map

I've created a minimal reproduction here: https://stackblitz.com/edit/react-ts-w4lkhv?file=MyMap.tsx

Steps to reproduce:

Expected Behavior

Should get a ref to the Map element.

Steps to Reproduce

https://stackblitz.com/edit/react-ts-w4lkhv?file=MyMap.tsx

Environment

Logs

No response

Pessimistress commented 1 year ago

useMap does not work outside of a Map or MapProvider.

Read http://visgl.github.io/react-map-gl/docs/api-reference/use-map

emekaokoli commented 1 year ago

This issue brought me here, I have done everything it always returns undefined. is there a fix for this?

pReya commented 1 year ago

This issue brought me here, I have done everything it always returns undefined. is there a fix for this?

The answer by @Pessimistress is correct: useMap() will only work inside components, that are children of the Map component. It will not work in the same component. For that you can just use React's useRef().

emekaokoli commented 1 year ago

Thank you for the quick response, I have tried the two methods all returned undefined

Using provider and useMap and using ref with useMap.

I need to access flyTo inside a tables onRowclick that is outside of the map children.

This issue brought me here, I have done everything it always returns undefined. is there a fix for this?

The answer by @Pessimistress is correct: useMap() will only work inside components, that are children of the Map component. It will not work in the same component. For that you can just use React's useRef().

geoffraymond commented 1 year ago

@emekaokoli there is a workaround and not ideal way (I also could not get it to work the way they are saying either).

const [thisMap, setThisMap] = React.useState();
...
<Map
  ...
 onLoad={(e) => setThisMap(e.target)}>
    <button
        style={{ position: 'absolute' }}
        onClick={(e) => {
          thisMap.flyTo({ center: [-122.4, 37.8], zoom: 14 });
        }}
      >
        Click me
      </button>
emekaokoli commented 1 year ago

@emekaokoli there is a workaround and not ideal way (I also could not get it to work the way they are saying either).

const [thisMap, setThisMap] = React.useState();
...
<Map
  ...
 onLoad={(e) => setThisMap(e.target)}>
    <button
        style={{ position: 'absolute' }}
        onClick={(e) => {
          thisMap.flyTo({ center: [-122.4, 37.8], zoom: 14 });
        }}
      >
        Click me
      </button>

Yes, I used that and passed it through useState, it does not produce the best result or maybe use a higher-order component and pass the locations as props.

klen commented 1 year ago

Same issue for me, my component is inside the Map, but useMap always returns undefined.

jmainhard commented 5 months ago

For anyone that has this problem, be sure to add an id attribute to the Map you are trying to reference. As the useMap documentation shows.

function Root() {
  return (
    <MapProvider>
      <Map id="myMap" ... />  // Here
      <NavigateButton />
    </MapProvider>
  );
}

Then you can reference it like this (from doc)

function NavigateButton() {
  const { myMap } = useMap(); // reference id

  const onClick = () => {
    myMap.flyTo({center: [-122.4, 37.8]});
  };

  return <button onClick={onClick}>Go</button>;
}