Reputation: 71
I want to achive the fly animation to different locations on a click event using mapbox. I have read in the docs that useMap provide the flyTo method that could do exactly what i want, but i keep getting undefined
I am a little bit lost on how to use the flyTo method, or if it works with the way i have setup mapbox with react. I find very little information about this topic on the internett tho.
This is the code i use:
import MapBox, { Marker, Popup, useMap } from "react-map-gl";
const Map = () => {
const { current: map } = useMap();
const { loading, error, data } = useLoading(
async () => await fetchJSON("APIURL")
);
console.log(data);
const [showPopup, setShowPopup] = useState(false);
const [changeViewport, setChangeViewport] = useState();
const [viewport, setViewport] = useState({
latitude: 59.913868,
longitude: 10.752245,
zoom: 4,
});
const handleLocations = (item) => {
map.flyTo({ center: [83, 23] });
console.log(item[1], item[0]);
};
if (!data) {
return "";
}
if (error) {
return <p>Error: {error.toString()}</p>;
}
return (
<Container>
<SubContainer>
<div
style={{
width: "100%",
padding: "0.5rem",
}}
>
<div
style={{
display: "flex",
padding: "1rem",
}}
>
<img src={zeiptLogo} alt="company logo" />
<Title>Enabled store locations</Title>
</div>
<div>
<Button>Oslo</Button>
<Button>Trondheim</Button>
<Button>Bergen</Button>
<Button>Vis alle</Button>
</div>
<Input>
<input type="text" />
</Input>
<Scroll>
{Object.keys(data)
.filter((value) => data[value])
.map((item) => {
return (
<>
<StoreNames
onClick={() => handleLocations(data[item].coords)}
>
<h4>{data[item].store_name}</h4>
<MdKeyboardArrowRight size={20} />
</StoreNames>
</>
);
})}
</Scroll>
</div>
<MapBox
mapboxAccessToken={MAPBOX_TOKEN_KEY}
initialViewState={viewport}
style={{ width: "100%", height: "100%" }}
mapStyle="mapbox://styles/mapbox/streets-v8"
movi
>
{Object.keys(data)
.filter((value) => data[value])
.map((item) => {
return (
<>
<Marker
longitude={data[item].coords[0]}
latitude={data[item].coords[1]}
anchor="bottom"
>
<HiLocationMarker size={35} color="#00519a" />
</Marker>
{showPopup && (
<Popup
longitude={data[item].coords[0]}
latitude={data[item].coords[1]}
anchor="bottom"
onClose={() => setShowPopup(false)}
>
You are here
</Popup>
)}
</>
);
})}
</MapBox>
</SubContainer>
</Container>
);
};
export default Map;
Upvotes: 5
Views: 4316
Reputation: 52
Both answers from red baha and Radi Mortada are correct.
To use flyto in your MapContainer, you need to attach a ref (mapRef) to the Map component.
To use flyto from the useMap hook, it needs to be used within a child component of the Map component, as useMap uses the forwarded mapRef from the parent.
import MapBox as Map from "react-map-gl";
const MapContainer = () => {
const mapRef = useRef(null)
// You can use mapRef?.current?.flyto(...) here in MapContainer
return <Map ref={mapRef} ... >
<Child />
</Map>
}
const Child = () => {
const { current: map } = useMap()
// You can use map?.flyto() here in Child.
// But only if it's a child component of <Map />!
// Otherwise map (= mapRef from parent) will be undefined.
return ...
}
Upvotes: 0
Reputation: 159
The useMap
hook is mostly useful when you want to access the map instance outside of the component that contains <MapBox />
. In your case, just use react refs:
const mapRef = useRef(null)
and then attach the ref to the MapBox component:
<MapBox
ref={mapRef} <= attach ref here
mapboxAccessToken={MAPBOX_TOKEN_KEY}
initialViewState={viewport}
style={{ width: "100%", height: "100%" }}
mapStyle="mapbox://styles/mapbox/streets-v8"
movi
>
Now you can use the flyTo
like this:
mapRef.current?.flyTo({ center: [83, 23] })
Upvotes: 6
Reputation: 164
const { current: map } = useMap();
map
will always be undefined
, as it is not in the context provider tree.
https://reactjs.org/docs/hooks-reference.html#usecontext
you can useMap
only in the components wrapped by <MapBox/>
in order to use the map instance you can use one of the following callback functions:
https://visgl.github.io/react-map-gl/docs/api-reference/map#callbacks
to store the map instance using useRef
onLoad={(event) => {
mapRef.current = event.target
}}
Upvotes: 1