如何正确导出MongoDB事件坐标数组至Google Maps组件?
问题分析与修复方案
你的问题核心在于全局变量无法触发React组件的重新渲染,而且组件初始化时异步数据还未加载完成,导致MapsComponent拿到的是空数组。以下是具体的修复方案:
问题根源
- 全局变量
locArray更新后,React不会自动通知MapsComponent重新渲染,组件始终停留在初始化时的空数组状态。 - 组件间数据传递违背了React的单向数据流原则,依赖全局变量会导致状态难以追踪和维护。
修复方案:状态提升到父组件
将数据获取逻辑统一放在父组件中,通过props将坐标数组传递给MapsComponent,确保数据变化时组件能自动更新。
步骤1:改造Listings组件,去掉全局变量
让Listings组件接收父组件传递的listings数据,不再自行处理API请求:
import List from '@mui/material/List'; import Paper from '@mui/material/Paper'; import Grid from '@mui/material/Grid' import Divider from '@mui/material/Divider'; import React from 'react'; import { Box } from '@mui/material'; export default function Listings({ listings, setFeaturedPosts }) { const updateFeaturedPost = (index, updatedPost) => { setFeaturedPosts((prevPosts) => { const newPosts = [...prevPosts]; newPosts[index] = updatedPost; return newPosts; }); }; return ( <React.Fragment> <Box elevation={0} style={{ height: '70vh', overflow: 'auto' }}> <List> {listings && listings.map((listing, index) => { const { orgname, title, date, description, startTime, endTime } = listing; return ( <React.Fragment key={listing._id}> <Paper elevation={4} style={{ width: '300px', p: 2, padding: '20px', marginBottom: '20px' }}> <Grid> {orgname} {title} {date} {description} {startTime} {endTime} </Grid> </Paper> <Divider /> </React.Fragment> ); })} </List> </Box> </React.Fragment> ); }
步骤2:创建父组件统一管理数据
在父组件中完成API请求,将listings数据分别传递给Listings和MapsComponent:
import React, { useEffect, useState } from 'react'; import axios from 'axios'; import dayjs from 'dayjs'; import Listings from './Listings'; import MapsComponent from './MapsComponent'; import { Grid } from '@mui/material'; export default function EventsPage({ setFeaturedPosts }) { const [listings, setListings] = useState(null); async function retrieveListings() { try { const res = await axios.post('http://localhost:5000/getevents', { loc: JSON.parse(localStorage.getItem('location')), nEvents: 10, startdate: dayjs().startOf('day'), enddate: dayjs().endOf('day'), eventtype: null }, { crossdomain: true }); if (res && res.status === 200) { setListings(res.data); } else { alert(res.data.message); } } catch (err) { alert('Failed to retrieve events: ', err.message); } } useEffect(() => { retrieveListings(); }, []); // 生成坐标数组,注意MongoDB的坐标是[经度, 纬度],Google Maps需要[纬度, 经度] const coordinates = listings ? listings.map(listing => ({ lat: listing.location.coordinates[1], lng: listing.location.coordinates[0] })) : []; return ( <Grid container spacing={2}> <Grid item xs={6}> <Listings listings={listings} setFeaturedPosts={setFeaturedPosts} /> </Grid> <Grid item xs={6}> <MapsComponent coordinates={coordinates} /> </Grid> </Grid> ); }
步骤3:修改MapsComponent接收props并响应变化
让MapsComponent监听coordinates props的变化,自动更新地图标记:
import React, { useEffect, useState } from 'react'; import { GoogleMap, LoadScript, Marker } from '@react-google-maps/api'; const containerStyle = { width: '600px', height: '600px', }; const center = { lat: 37.7749, lng: -112.4194, }; function MapsComponent({ coordinates }) { const [markers, setMarkers] = useState([]); useEffect(() => { // 当坐标数组更新时重新生成标记 setMarkers( coordinates.map((location, index) => ({ key: index, position: location, })) ); }, [coordinates]); // 依赖coordinates,确保数据变化时触发更新 return ( <> <LoadScript googleMapsApiKey="API-key"> <GoogleMap mapContainerStyle={containerStyle} center={center} zoom={15}> <Marker position={center} /> {markers.map((marker) => ( <Marker key={marker.key} position={marker.position} /> ))} </GoogleMap> </LoadScript> </> ); } export default React.memo(MapsComponent);
关键注意事项
- 坐标格式转换:MongoDB存储的坐标是
[经度, 纬度],而Google Maps需要{lat: 纬度, lng: 经度},必须调换顺序否则标记位置会错误。 - React数据流:通过props传递状态是React的标准做法,能确保状态变化时组件自动重新渲染,避免全局变量带来的不可预测性。
- useEffect依赖:在MapsComponent的useEffect中添加
coordinates作为依赖,确保坐标数组更新时立即同步地图标记。
内容的提问来源于stack exchange,提问作者Emily
相关产品推荐
相关产品推荐

