React-Leaflet, Change zoom and position according to object array

151 Views Asked by At

So this is my MapComponent, I have added logic wherein whatever is inputted in the search bar it will display those school that is in an array, what I wanna do is add some zoom and change position effect whenever the button is clicked <button type="button" onClick={() => updateMapCenterZoom(value.position, 15)}> but still it doesn't work with setView or any other tips

 const [query, setQuery] = useState("");
  const [position, setPosition] = useState([14.389786, 121.047566]);
  const [mapZoom, setMapZoom] = useState(13);

  const filteredSchools = schoolData.filter((val) => {
    if (query === "") {
      return val;
    } else {
      return (
        val.name.toLowerCase().includes(query.toLowerCase()) ||
        val.type.toLowerCase().includes(query.toLowerCase())
      );
    }
  });

  const updateMapCenterZoom = (newCenter, newZoom) => {
    setPosition(newCenter);
    setMapZoom(newZoom);
    
  };

and this is where it returns from MapComponent(React Component)

<MapContainer preferCanvas center={position} zoom={mapZoom} scrollWheelZoom={false}>
            <TileLayer
              attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
              url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
            />
             {filteredSchools.map((value, key) => (
              <Marker
                key={value.id}
                position={value.position}
                eventHandlers={{ click: (e) => handleMarkerClick(e, value) }}>
                  <Popup>{value.name}</Popup>
                </Marker>
                
                ))}
                
          </MapContainer>

and outside this I have this function where in it creates and automates the suggestion according to the search query NOTE: the <MapContainer /> and the <div id='school-container'/> tags are both inside the return statement of MapComponent

<div id="school-container">
              {filteredSchools.map((value, key) => (
                <div key={key}>
                  <div className="border border-white-500 min-w-[10pc] w-[25pc] max-w-[30pc] text-white p-3 flex flex-row items-center hover:bg-amber-600">
                    <Link to={value.link}>
                      <img src={value.image} alt="logo" className="w-20 l-10 m-2" />
                      <div className="flex flex-col space-y-3 xs:text-xs sm:text-s md:text-m lg:text-l text-start">
                        <div className="color-white">{value.name}</div>
                        <div className="color-white">{value.type}</div>
                      </div>
                    </Link>
                    <button type="button" onClick={() => updateMapCenterZoom(value.position, 15)}>
                      See Location
                    </button>
                  </div>
                </div>
              ))}

This should have worked, I also tried adding console.log to see if it receives the latlng and the zoom, somehow it outputs it but doesn't change the map scene

this is also a sample of the school.js

export const schoolData = [
    {
        id: 1,
        name: "School 1",
        type: "Public University",
        address: "92QG+M5V, University Rd, Poblacion, Muntinlupa, Metro Manila",
        image: plmunLogo,
        link: "/dummy-website",
        coordinates:{ 
        lat:  14.389101, 
        lang: 121.025299
        }
    },
    {
        id:2,
        name: "School 2",
        type: "Private School",
        address: "Km.30 National Road, Tunasan, Muntinlupa, 1773 Metro Manila",
        image: loaiLogo,
        link: "/dummy-website2",
        coordinates: 
        {lat: 14.3730, 
        lang:121.0474}
    },
    {
        id:3,
        name: "San Beda College Alabang",
        type: "Private School",
        address: "8 Don Manolo Blvd, Cupang, Muntinlupa, 1770 Metro Manila",
        image: sbcaLogo,
        link: "/dummy-website3",
        coordinates: 
        {lat: 14.433810, 
        lang:121.026817}
    }]
export default schoolData;
1

There are 1 best solutions below

9
On

After researching similar questions about react-leaflet I found that moving the map works a bit different than expected.

The useMap and useMapEvents references only work in children of the <MapContainer /> component. Besides that, if you need a reference to the map you'll need to use the whenCreated property on the MapContainer to store a reference of the map in a state. See example.

With this in mind, we can move the map by generating a reference to it and then call the Leaflet commands like setView or flyTo to move and zoom to the point in the map.

I've created a summarized example of how this all is implemented.

import { MapContainer } from 'react-leaflet';
import { useState, useCallback } from 'react';

const MapComponent = () => {
  const [map, setMap] = useState(null);

  const updateMapCenterZoom = useCallback((newCenter, newZoom) => {
    if (map !== null) {
      map.setView(newCenter, newZoom);
    }
  }, [map]);

  return (
    <>
      <MapContainer
        preferCanvas
        center={[14.389786, 121.047566]}
        zoom={13}
        scrollWheelZoom={false}
        whenCreated={setMap}
      />

      <button type="button" onClick={() => updateMapCenterZoom([14.389786, 121.047566], 15)}>
        See Location
      </button>
    </>
  );
};

export default MapComponent