I am trying to implement some simple movement controls on a react-leaflet map to allow "flying" to a set of predefined coordinates after pressing a button.
I'm aware that the Map
instance created by react-leaflet can be accessed by child components and so I'm utilising the useMap()
hook in a child component to achieve this as follows in NavigateToMarker.jsx
:
import { useMap } from "react-leaflet";
export default function NavigateToMarker({position}) {
const map = useMap();
map.flyTo(position, 13)
return null
}
MainMap.jsx
looks like this:
import NavigateToMarker from './NavigateToMarker';
export default function MainMap() {
const [position, setPosition] = React.useState([51.607642, -0.129303])
const handleClick = (position) => {
setPosition(position)
}
<MapContainer>
<TileLayer />
<GeoJSON data={geoJsonData} />
<NavigateToMarker position={position} />
</MapContainer>
<Button onClick={() => handleClick([52.309611, -0.139303])}>Fly To Position</Button>
}
The button does fly to the specified position but my problem is that the NavigateToMarker
code is ran every time the MainMap
component renders.
I've tried including the button inside NavigateToMarker
but because this component is then placed within a MapContainer
component, the buttons don't show and I'm not sure how easily I'd be able to apply an CSS gridding and styling with this method.
Is there a way to ensure that NavigateToMarker
is only invoked when the button in MainMap.jsx
is clicked?
As suggested by @EzioMercer, wrapping NavigateToMarker
in the memo function yielded the desired behavhaviour.
//NavigateToMarker.jsx
import { useMap } from "react-leaflet";
import { memo } from 'react';
export default memo(function NavigateToMarker({position, clicked}) {
const map = useMap();
if(clicked) map.setView(position, 13)
return null
})
To prevent NavigateToMarker
running on initial render, I added a boolean prop that's only set to true after the onClick()
handler on the button is invoked.
//MainMap.jsx
import NavigateToMarker from './NavigateToMarker';
export default function MainMap() {
const [position, setPosition] = React.useState([51.607642, -0.129303])
const [clicked, setClicked] = React.useState(false)
const handleClick = (position) => {
setClicked(true)
setPosition(position)
}
<MapContainer>
<TileLayer />
<GeoJSON data={geoJsonData} />
<NavigateToMarker position={position} clicked={clicked} />
</MapContainer>
<Button onClick={() => handleClick([52.309611, -0.139303])}>Fly To Position</Button>
}