如何在React-leaflet中实现点击Marker后调整右侧列表排序?
实现点击Marker置顶对应列表项的方案
核心思路
- 统一在App组件中管理地图点位数据,避免Map和List重复请求Firestore导致的数据不一致
- 使用文档ID作为选中标识(比索引更可靠,不会因排序变化失效)
- 在List组件中根据选中ID重新排序数组,将选中项移至首位
修改后的代码
App.js
import { useState, useEffect } from 'react'; import { query, collection, onSnapshot } from 'firebase/firestore'; import { db } from './firebase'; // 请替换为你的Firebase配置文件路径 function App() { const [houses, setHouses] = useState([]); const [selectedHouseId, setSelectedHouseId] = useState(null); // 仅在App组件中请求一次Firestore数据 useEffect(() => { const q = query(collection(db, "map-markers")); const unsubscribe = onSnapshot(q, (querySnapshot) => { const houseData = querySnapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })); setHouses(houseData); }); // 组件卸载时清理Firestore订阅 return unsubscribe; }, []); return ( <div className="App"> <Header /> <div className="map-content"> <Map houses={houses} onSelect={setSelectedHouseId} /> <List houses={houses} selectedHouseId={selectedHouseId} /> </div> </div> ); }
Map.js
import { Marker, MapContainer, TileLayer } from 'react-leaflet'; const Map = ({ houses, onSelect }) => { // 替换为你的地图中心坐标 const center = [39.9042, 116.4074]; 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" /> {houses.map((house) => ( <Marker key={house.id} eventHandlers={{ click: () => { onSelect(house.id); // 传递选中点位的文档ID }, }} position={[parseFloat(house.lat), parseFloat(house.lon)]} icon={defaultIcon} /> ))} </MapContainer> </div> ); };
List.js
const List = ({ houses, selectedHouseId }) => { // 排序逻辑:将选中项移至数组首位 const sortedHouses = [...houses]; if (selectedHouseId) { const targetIndex = sortedHouses.findIndex(house => house.id === selectedHouseId); if (targetIndex !== -1) { const selectedItem = sortedHouses.splice(targetIndex, 1)[0]; sortedHouses.unshift(selectedItem); } } return ( <div style={{ width: "50%" }}> {sortedHouses.map((house) => ( <ListItem key={house.id} title={house.title} /> ))} </div> ); };
关键优化点
- 减少重复请求:避免Map和List各自请求Firestore数据,提升性能并保证数据一致性
- 可靠的选中标识:使用Firestore文档ID代替数组索引,防止因数组排序导致的选中错误
- 高效排序逻辑:通过
splice和unshift操作快速调整选中项位置,保持其余项原顺序 - 内存泄漏防护:在App组件中清理Firestore实时订阅,避免组件卸载后无效监听
内容的提问来源于stack exchange,提问作者userName
相关产品推荐
相关产品推荐

