Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use .getMap() outside of Map Component #904

Closed
l3git9 opened this issue Oct 3, 2019 · 10 comments
Closed

Use .getMap() outside of Map Component #904

l3git9 opened this issue Oct 3, 2019 · 10 comments

Comments

@l3git9
Copy link

l3git9 commented Oct 3, 2019

Hi,

Working on a project that is getting quite large and I was wondering if there is a simple solution to using the map outside of the component. At the moment I am using a ref in order to use getMap() within the map component, but I have a search function that needs to flyTo the location when the user clicks on the result and I would like to be able to do so within another component. Is that possible or is everything going to need to funnel back into the Map component? I've looked everywhere for an example and have found nothing so I believe that I won't to in the manner that I want to do it. If I can't that's fine, but it would suck if there is and I just absolutely pass it up only to make it more complicated.

@mayteio
Copy link

mayteio commented Oct 8, 2019

I use context inside React to get access to the map instance:

// MapContext.js
import React, {createContext, useState} from 'react';

// create context object
const MapContext = createContext();

// handle state in your provider and pass it as the value
export function MapProvider(props){
  const [map, setMap] = useState();
  return <MapContext.Provider value={[map, setMap]} {...props} />
}

// expose a helper hook to easily grab the state anywhere in your app
// This is an excellent pattern to share state without redux - and be 
// wary of how you can optimise it:
// https://kentcdodds.com/blog/how-to-optimize-your-context-value
export function useMap(){
  const context = useContext(MapContext);
  if(context === undefined) throw Error('You forgot to wrap your app with <MapProvider />');
  return context;
}

// App.js
import React from 'react';
import {MapProvider} from './MapContext';

export default function App(){
  const [, setMap] = useMap();
  return (
    <MapProvider>
      <Example />
      <ReactMapGL
        ...
        ref={ref => ref && setMap(ref.getMap())}
      />
    </MapProvider>
  )
}

// Example.js
import React from 'react';
import {useMap} from './MapContext';

export default function Example(){
  // get the map instance outside the component and do whatever!
  const [map] = useMap();
  const onClick = () => {
    map && map.flyTo(...);.
  }

  useEffect(() => alert('map ready!'), [map])

  return <button onClick={onClick}>Fly like a bird</button>
}

Note; I have switched between using useRef and useState to store the context. They both seem to have tradeoffs; useRef is probably the intended usage according to dan, but this makes it difficult to listen to it actually being set, i.e. with useEffect. Depending on ref.current is problematic though.

useState on the other hand will trigger an effect re-run. Mutations to the map object should not trigger a re-render because it's the same object, just mutated.

Maybe a feature request to expose a useMap hook? 🙏 @Pessimistress accepting pull requests for hooks in this library? Don't think there are any just yet.

@edonadei
Copy link

edonadei commented May 5, 2020

Hello ! I would like to re-open this one, i'm having issue with own code base to get ref on the map to use the method flyTo. The example ahead just does not work, my code simplified

import ReactMapboxGl, { Layer, Feature, Marker } from "react-mapbox-gl";

const Map = ReactMapboxGl({
  accessToken: process.env.REACT_APP_MAPBOX_API
});

<Map
        // eslint-disable-next-line
        ref={ref => console.log(ref)}
        style="mapbox://styles/mapbox/streets-v9"
        containerStyle={{
          height: "93vh",
          width: "100%"
        }}
      />

I tried to find the method flyTo in this ref, but could not find it.

@mayteio
Copy link

mayteio commented May 5, 2020

This is not going to work because you’re trying to instantiate a component instead of render it. Use it as a component and pass mapboxApiAccessToken as a prop instead.

@edonadei
Copy link

edonadei commented May 5, 2020

Sorry for your fast answer @mayteio, just a mistake from me, i've just mistaken your library with react-mapbox-gl !!

@Pessimistress
Copy link
Collaborator

Maybe a feature request to expose a useMap hook?

Yes! All PRs welcomed.

@mayteio
Copy link

mayteio commented May 18, 2020

I'd be happy to @Pessimistress. What are your thoughts on API design? My solution above requires a context (I think all solutions would?) to provider the ref down to other components. That would mean introducing a <MapRefProvider /> or something, increasing API surface. Are you opposed to this approach?

I'll open and work on a PR and we can discuss there.

@Pessimistress
Copy link
Collaborator

MapContext will be available in v5.3/v6.1. You can try it with 6.1.0-beta.1.

@emekaokoli
Copy link

Hello, my problem landed me here. please can anyone help me with this?
#1983

the map renders but it does not update the mapref when I click to open the modal thereby making the mapref.current null which means I cannot access flyTo() or setCenter()

I will greatly appreciate all the help I can get.

thanks.

@bertearazvan
Copy link

MapContext will be available in v5.3/v6.1. You can try it with 6.1.0-beta.1.

It's not exported anymore unfortunately, I guess since v7?

@chris-wasowicz
Copy link

Bump, I would also like to find some good way of accessing the Map outside of the Map component children. As @bertearazvan mentioned, MapContext is no longer exported. Any other way @Pessimistress ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants