react-google-maps数组为空时Marker仍显示的问题求助
问题:react-google-maps 空数组时标记未移除
我在GoogleMapComponent.js中使用react-google-maps组件,根据similarLocations属性渲染多个Marker。初始渲染时数组为空,地图无标记;父组件CreateLocation.js中用户输入触发请求,返回的相似位置数组传给子组件后,标记能正常显示。但当用户输入导致请求返回空数组时,尽管确认props传递的是空数组,之前的标记仍保留在地图上,请问如何在数组为空时移除标记?
父组件CreateLocation.js代码
import React, { useEffect, useState } from 'react' import Input from '../../../components/input' import { checkLocationMatches} from '../api' import GoogleMapComponent from './GoogleMapComponent' const CreateLocation = ({ isEdit, }) => { const [locationData, setLocationData] = useState({ id: null, client: null, locationName: '', googleLocationDetails: '', nameAr: '', nameEn: '', street: '', description: '', category: null, clientCode: '', tags: [], lat: 0, lang: 0, gov: '', city: '', area: '' }) const [similarLocations, setSimilarLocations] = useState([]) const matchArabicName = async () => { try { const data = { lat: locationData.lat, lang: locationData.lang, clientId: locationData.client.value, matcher: 'name_ar', name: locationData.nameAr } const response = await checkLocationMatches(data) response.data ? setSimilarLocations(response.data) : setSimilarLocations([]) } catch (err) { console.log(err.response, 'match err') } } useEffect(() => { if (locationData.lat !== 0 && locationData.nameAr.length > 0 && !isEdit) { matchArabicName() } // eslint-disable-next-line react-hooks/exhaustive-deps }, [locationData.lat, locationData.nameAr]) return ( <Container> <Body> <Form> <Input disableWithBorder={false} label="Client Location Name (Arabic)" name="nameAr" placeholder="EX: Hyper one" type="text" value={locationData.nameAr} onChange={e => handleLocationDetailsChange(e)} required isEditable /> </Form> <MapContainer> <GoogleMapComponent isMarkerShown containerElement={ <div style={{ height: '100%', width: '100%' }} /> } setMapLocationData={handleSetMapLocationData} lat={locationData.lat} lang={locationData.lang} isOpen={true} similarLocations={similarLocations} /> </MapContainer> </Body> </Container> ) } export default CreateLocation
子组件GoogleMapComponent.js代码
/* eslint-disable eqeqeq */ import React, { useEffect, useState } from 'react'; import { compose, withProps } from 'recompose'; import { withScriptjs, withGoogleMap, GoogleMap, Marker, InfoWindow } from 'react-google-maps'; import MapMarker from '../../../assets/icons/map-marker.svg' import SimilarMarkerIcon from '../../../assets/icons/similar-marker.svg' const GoogleMapComponent = compose( withProps({ googleMapURL: 'https://maps.googleapis.com/maps/api/js?key=API_KEY®ion=EG&language=ar&v=3.exp&libraries=geometry,drawing,places', loadingElement: <div style={{ height: `100%` }} />, mapElement: <div style={{ height: `100%` }} />, }), withScriptjs, withGoogleMap, )(({ isMarkerShown, multipleMarkers, similarLocations, readOnly }) => { useEffect(() => { console.log(similarLocations, 'Similar locations') console.log(similarLocations.length, 'Similar locations length') }, [similarLocations]) const onMarkerDragEnd = (coord) => { const { latLng } = coord; const lat = latLng.lat(); const lng = latLng.lng(); setCurrentPosition({ lat: lat, lang: lng }); getReverseGeocodingData(lat, lng); }; return ( <GoogleMap defaultZoom={zoom || 12} zoom={zoom || 12} center={{ lat: currentPosition.lat, lng: currentPosition.lang }} onClick={(e) => onMarkerDragEnd(e)}> {isMarkerShown && !multipleMarkers && ( <Marker position={{ lat: currentPosition.lat, lng: currentPosition.lang }} defaultDraggable={!readOnly} onDragEnd={(e) => onMarkerDragEnd(e)} options={{ icon: { url: MapMarker, }, }} /> )} { similarLocations.length > 0 && similarLocations.map(marker => ( <Marker key={marker.location.id} position={{ lat: +marker.location.latitude, lng: +marker.location.longitude }} onClick={() => { handleActiveMarker(marker.location.id) }} options={{ icon: { url: SimilarMarkerIcon, }, }} visible={similarLocations.includes(marker)} > {activeMarker === marker.location.id ? ( <InfoWindow onCloseClick={() => setActiveMarker(null)}> <div>{marker.location.name_ar}</div> </InfoWindow> ) : null} </Marker> )) } </GoogleMap> ); }); export default GoogleMapComponent;
解决方案
1. 移除冗余的visible属性
Marker上的visible={similarLocations.includes(marker)}是问题核心:当similarLocations变为空数组时,这个判断无法正确标记标记为不可见,而且数组更新时对象引用变化会导致includes判断失效。直接删除该属性,让渲染逻辑完全由数组的map方法控制——空数组调用map不会生成任何Marker元素。
2. 优化渲染判断(可选)
原代码中similarLocations.length > 0 &&的判断可以保留,但即使去掉,空数组的map也不会渲染内容,不影响结果。保留的话可以减少不必要的map执行。
3. 检查内部状态的影响
子组件中使用的currentPosition、zoom、activeMarker等状态需确保定义正确,且handleActiveMarker、setActiveMarker能正确重置弹窗状态,避免InfoWindow残留。
修改后的子组件关键代码
// ... 其他代码不变 return ( <GoogleMap defaultZoom={zoom || 12} zoom={zoom || 12} center={{ lat: currentPosition.lat, lng: currentPosition.lang }} onClick={(e) => onMarkerDragEnd(e)}> {/* 主标记渲染逻辑 */} {isMarkerShown && !multipleMarkers && ( <Marker position={{ lat: currentPosition.lat, lng: currentPosition.lang }} defaultDraggable={!readOnly} onDragEnd={(e) => onMarkerDragEnd(e)} options={{ icon: { url: MapMarker, }, }} /> )} {/* 相似位置标记渲染逻辑 */} {similarLocations.length > 0 && similarLocations.map(marker => ( <Marker key={marker.location.id} position={{ lat: +marker.location.latitude, lng: +marker.location.longitude }} onClick={() => { handleActiveMarker(marker.location.id) }} options={{ icon: { url: SimilarMarkerIcon, }, }} > {activeMarker === marker.location.id ? ( <InfoWindow onCloseClick={() => setActiveMarker(null)}> <div>{marker.location.name_ar}</div> </InfoWindow> ) : null} </Marker> ))} </GoogleMap> ); // ... 其他代码不变
验证要点
- 确认父组件中
setSimilarLocations传入的是新数组(如response.data或[]),确保props引用变化触发子组件重新渲染。 - 测试用户输入导致返回空数组的场景,观察地图上的相似位置标记是否完全移除。
内容的提问来源于stack exchange,提问作者Mohamed Karawia
相关产品推荐
相关产品推荐

