如何使用 useMapEvents 将视图集中到新标记?

How to center view to new Markers with useMapEvents?

让我总结一下我正在开发的应用程序:

我正在创建一个 React 应用程序,用于根据您的年龄、性别和您居住的城市寻找足球俱乐部。

目前它工作正常,但我希望地图在新标记出现在结果中时将视图居中。

我读到我们必须在 MapContainer 上使用 {WhenCreated} 初始化中心,并使用 useMapEvents 来处理视图的更新,但我无法嵌套它或者我失去了我的范围标记数组..

这是我的代码:

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("https://api-clubs-cvl.herokuapp.com/cities")
            .then((res) => {
                let result = [];
                res.data.forEach(element => {
                    result.push({ label: element.name })
                });
                setallcities(result)
            })
    }, []);

    useEffect(() => {
        axios.get("https://api-clubs-cvl.herokuapp.com/categories")
            .then((res) => setCategories(res.data))
    }, [])

    useEffect(() => {
        axios.get("https://api-clubs-cvl.herokuapp.com/allteams").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="http://osm.org/copyright">OpenStreetMap</a> contributors'
                            url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
                        />
                           
                        <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
                                id="combo-box-demo"
                                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;

您可以在这里找到要点:https://gist.github.com/ManuelWCS/4e67a75fc9a1053ed6f1ff095225ea0c

如果您想观看演示,请单击 here

感谢您的阅读,如果您有任何问题或解决方案,请联系我!

:)

你不需要useMapEvents。您也可以仅使用地图实例来完成此操作。

首先使用whenCreatedprop获取地图实例 在 filterSearch 函数中检查两种情况。如果 resultofSearch 数组为空且没有可用位置,那么您需要 return 并发出警报。 否则,使用可用标记中的所有坐标并围绕所有这些坐标缩放地图。您可以使用 fitBounds Leaflet 方法实现。

 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 包含您的部分应用程序