On the page on the left side I have a map and on the right side I have a list of places. Markers for the map and a list of places comes to me from the database. I need to track the map zoom to filter the list of places and remove those places whose markers are not visible. How can i do this? How can I track the map zoom and implement such logic?
const Map = ({ onSelect }) => { const [coordinates, setCoordinates] = useState([]); useEffect(() => { const q = query(collection(db, "map-markers")); onSnapshot(q, (querySnapshot) => { setCoordinates( querySnapshot.docs.map((doc) => ({ id: doc.id, data: doc.data(), })) ); }); }, []); return ( <div style={{ width: "100%" }}> <MapContainer center={center} zoom={13} scrollWheelZoom={false} style={{ height: "100vh" }} > <TileLayer attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" /> {coordinates.map((coord, index) => ( <Marker key={index} eventHandlers={{ click: () => { onSelect(index); }, }} position={[parseFloat(coord.data.lat), parseFloat(coord.data.lon)]} icon={defaultIcon} /> ))} </MapContainer> </div> ); };
const List = ({ selectedHouse }) => { const [houseTitles, setHouseTitle] = useState([]); useEffect(() => { const q = query(collection(db, "map-markers")); onSnapshot(q, (querySnapshot) => { setHouseTitle( querySnapshot.docs.map((doc) => ({ id: doc.id, data: doc.data(), })) ); }); }, []); return ( <div style={{ width: "50%" }}> {houseTitles.map((title, index) => ( <ListItem key={index} title={title.data.title} /> ))} </div> ); };
Assuming your components are structured as follows:
<Parent>
<List />
<Map />
</Parent>
you could lift the state up into the Parent
component (so Parent
is responsible for fetching the data and storing it in React's useState
). You would need to define 2 states: allHouses
(the complete list of houses) and visibleHouses
(the houses in view based on the map bounds):
const [allHouses, setAllHouses] = useState([
{
id: 1,
data: {
title: 'House 1',
lat: 52.074,
lon: 5.217,
},
},
{
id: 2,
data: {
title: 'House 2',
lat: 52.07222,
lon: 5.221965,
},
},
{
id: 2,
data: {
title: 'House 3',
lat: 52.07,
lon: 5.215,
},
},
]);
const [visibleHouses, setVisibleHouses] = useState(allHouses);
For simplicity, I've hardcoded the data rather than fetching it from an API.
The state can then be passed down to the List
and Map
components:
<List visibleHouses={visibleHouses} />
<Map
...
allHouses={allHouses}
setVisibleHouses={setVisibleHouses}
/>
Only the visibleHouses
need to be passed to the List
component as we only want to display a list of the ones visible based on the map bounds. We'll need to pass allHouses
along with the setVisibleHouses
state setter to the Map
component so that we can render all the houses on the map, and update the list of visible houses as the user moves or zooms the map.
You can use events to listen for either a map move ( dragend
) or a zoom event ( zoomend
) and then update the visibleHouses
based on whether each house is in the current bounds of the map
:
function MyComponent() {
const map = useMapEvents({
dragend: () => {
console.log('moved');
setVisibleHouses(
allHouses.filter((c) =>
map.getBounds().contains({ lat: c.data.lat, lng: c.data.lon })
)
);
},
zoomend: () => {
console.log('zoomed');
setVisibleHouses(
allHouses.filter((c) =>
map.getBounds().contains({ lat: c.data.lat, lng: c.data.lon })
)
);
},
});
return null;
}
Because the List
component renders the visibleHouses
, whenever this state is updated as the result of a map move or zoom, it will cause the list to be updated accordingly.
This StackBlitz shows a working demo of this.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.