Let me summarize the app I am working on :

I am creating a React app for finding a soccer club depending on your age, gender and the city where you live.

It works fine for now, but I want the map to center the view on the new markers when they appear in the results.

I've read that we have to initialize the center with {WhenCreated} on the MapContainer, and use useMapEvents to handle the update of the view but I can't manage to nest it or I loose the range of my array of marker..

Here is my code :

import React, { useState, useEffect } from "react"; import Header from "../header/Header"; import "./Moible3.css"; import { MapContainer, TileLayer, Marker, Popup, useMapEvents } from "react-leaflet"; import TextField from "@mui/material/TextField"; import Autocomplete from "@mui/material/Autocomplete"; import FormControlLabel from "@mui/material/FormControlLabel"; import FormControl from "@mui/material/FormControl"; import Radio from "@mui/material/Radio"; import RadioGroup from "@mui/material/RadioGroup"; import btnPicture from "../../assets/Boutons/buttontransparent.png"; import axios from "axios"; import Geolocalisation from "../Hook/Geolocalisation"; import MarkerClusterGroup from "react-leaflet-markercluster"; import Footer from '../../components/Footer/Footer.jsx'; import L from "leaflet"; function Mobile3() { const [allcities, setallcities] = useState([]); const [categories, setCategories] = useState([]); const [allteams, setallTeams] = useState([]); const [clubSearch, setclubSearch] = useState([]); const [formData, setformData] = useState({ age: null, city: "", type: 'Libre', gender2: '', category: "", }) const filterSearch = (e) => { e.preventDefault(); let categorieWanted = categories.filter( (categorySelected) => (formData.gender2 === categorySelected.gender && formData.age >= categorySelected.minAge && formData.age <= categorySelected.maxAge && formData.type === categorySelected.type)) const resultofSearch = allteams.filter((clubWanted) => clubWanted.Category === categorieWanted[0].name && clubWanted.Localite === formData.city); setclubSearch(resultofSearch); console.log(resultofSearch)} const handleChange = (e) => { setformData({ ...formData, [e.target.name]: e.target.value }) } useEffect(() => { axios.get("") .then((res) => { let result = []; res.data.forEach(element => { result.push({ label: element.name }) }); setallcities(result) }) }, []); useEffect(() => { axios.get("") .then((res) => setCategories(res.data)) }, []) useEffect(() => { axios.get("").then((res) => setallTeams(res.data)) }, []) return ( <div className="fullPage"> <Header /> <div className="subContainer"> <h1 className="titlePart1">Trouvez un club près </h1> <h1 className="titlePart2">de chez vous ! </h1> <main className="mapContainer"> <MapContainer className="mapLeaflet" center={[48.856614, 2.3522219]} zoom={13} scrollWheelZoom={true} doubleClickZoom={true} zoomControl={true} > <TileLayer attribution='&copy; <a href="">OpenStreetMap</a> contributors' url="" /> <Geolocalisation /> <MarkerClusterGroup animate={true} onClusterClick={(cluster) => console.warn( "cluster-click", cluster, cluster.layer.getAllChildMarkers() ) } > {clubSearch.length !== 0 ? clubSearch.slice(0, 100).map((res, index2) => { return ( <Marker key={index2} position={[res.Latitude, res.Longitude]} > <Popup key={index2}> <p> {res.Club}</p> </Popup> </Marker>) }) : null } </MarkerClusterGroup> </MapContainer> </main> <div className="legendAndForm"> <section className="legendMap"> <p className="legend"> Entrez votre <em className="birthday">date de naissance </em>et la{" "} <em className="ranked"> compétition </em> souhaitée pour découvrir les clubs à proximité !{" "} </p> </section> <div className="filtrations"> <form className="filtrationsWrapper" onSubmit={(e) => filterSearch(e)}> <div className="filtre1"> <span className="filterTitle1">VOTRE ÂGE </span> <TextField label="Âge" type="number" margin="normal" name="age" onChange={(e) => { handleChange(e) }} helperText="Renseingez votre aĝe ici" focused inputProps={{ inputMode: "numeric", pattern: "[0-9]*", placeholder: "10, 15, 30...", }} /> </div> <div className="filtre2"> <FormControl component="fieldset"> <span className="filterTitle2">COMPETITION :</span> <RadioGroup row aria-label="gender" defaultValue="female" name="gender2" error="Vous devez renseigner une compétition" onChange={(e) => handleChange(e)} required={true} > <FormControlLabel value="Male" className="radio1" control={<Radio />} label="Masculine" /> <FormControlLabel className="radio1" value="Female" control={<Radio />} label="Feminine" /> </RadioGroup> </FormControl> </div> <div className="filtre3"> <span className="filterTitle3"> VOTRE VILLE </span> <Autocomplete disablePortal inputValue={formData.city} options={allcities} noOptionsText="Pas d'élement correspondant" onInputChange={(event, newInputValue) => { setformData({ ...formData, city: newInputValue }); }} sx={{ width: 250 }} renderInput={(params) => ( <TextField {...params} label="Rechercher" /> )} /> <div className="hiddenSearchResult" id='hidden'> <p className="resultError"> Nique ta mère</p> </div> </div> <div className="btnContainer" id='test'> <button className="btnBackground" type="submit"> <img className="findclubBtn" alt="trouvez votre club" src={btnPicture} /> </button> </div> </form> </div> <div className="resul"> {clubSearch.length !==0 ? clubSearch.map((clubSelected, Uniqueindex) => { return ( <div className="cardResult" key={Uniqueindex}> <div className="titleContainer"> <span className="titleCard"> {clubSelected.name} </span> </div> <div className="columnContainer"> <div className="column1"> <div className="logo1"></div> <div className="logo2"></div> <div className="logo3"></div> </div> <div className="column2"> <div className="info1"> {clubSelected.Mail}</div> <div className="info2">{clubSelected.Adresse}</div> <div className="info3">Voir plus d'infos</div> </div> </div> </div>) }) : null } </div> </div> <Footer/> </div> </div> ); } export default Mobile3;

You can find a gist here :

If you want to see a demo click here

Thanks for your reading, please hit me up if you have questions or solutions !

:)

1 Answer

You do not need useMapEvents. You can do it alternatively using the map instance only.

Take the map instance first using whenCreated prop Inside filterSearch function check for two cases. Once if resultofSearch array is empty there are no available locations, then you need to return and alert something. Otherwise, use all the coordinates from the available markers and zoom the map around all these coordinates. You can achieve that using fitBounds Leaflet method.

 const [map, setMap] = useState(null); ... <MapContainer whenCreated={setMap} /> ... const filterSearch = (e) => { ... if (resultofSearch.length === 0) return alert("There are no available locations"); const arrayOfLatLngs = resultofSearch.map(({ Latitude, Longitude }) => [ Latitude, Longitude ]); const bounds = L.latLngBounds(arrayOfLatLngs); if (map) map.fitBounds(bounds); } 

Demo with part of your app

3

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.