GoogleMapReact的onGoogleApiLoaded在state变化时不重新渲染如何解决
问题原因
onGoogleApiLoaded 仅在谷歌地图API首次加载完成时触发一次,你在其中创建的Circle实例没有被持久化存储,后续state变更时也没有对应的更新逻辑触发,因此样式不会同步变化。
解决方案
- 用
useRef存储地图实例、maps对象和所有圆圈实例的引用,避免重复创建,同时方便后续更新操作 - 拆分初始化创建圆圈和更新圆圈属性的逻辑
- 通过
useEffect监听依赖项(比如tag、geoFencesSites)的变化,依赖变更时批量更新所有圆圈的属性
修改后的代码示例:
import { useRef, useEffect, useState } from 'react' import _ from 'lodash' import GoogleMapReact from 'google-map-react' // 其他原有业务逻辑保留 const tags = [allJobsTag].concat(settings.jobs.filter((job) => !job.deleted)); const [tag, setTag] = useState(allJobsTag); // 新增ref存储必要引用 const mapRef = useRef(null) const mapsRef = useRef(null) const circlesRef = useRef([]) function renderGeoFences() { const map = mapRef.current const maps = mapsRef.current if (!map || !maps) return // 清空之前的圆圈实例,避免重复渲染 circlesRef.current.forEach(circle => circle.setMap(null)) circlesRef.current = [] // 重新创建所有圆圈 _.map(geoFencesSites, (site) => { let circle = new maps.Circle({ strokeColor: tag.id==='all-jobs'?"orange":'#1aba8b26', strokeOpacity: 1, strokeWeight: 4, fillColor: '#1aba8b1f', fillOpacity: 1, map, center: { lat: Number(site.location.latitude), lng: Number(site.location.longitude) }, radius: site.fenceSize, }); circlesRef.current.push(circle) }); } let apiIsLoaded = (map, maps) => { // 存储实例到ref mapRef.current = map mapsRef.current = maps renderGeoFences(); }; // 新增useEffect,依赖变化时触发重新渲染围栏 useEffect(() => { renderGeoFences() }, [tag, geoFencesSites]) // 所有影响围栏渲染的变量都要加入依赖数组 return( <GoogleMapReact zoom={getMapZoom()} center={{ lat: centerLatitude, lng: centerLongitude }} options={{ fullscreenControl: false, zoomControlOptions: { position: 3 }, }} yesIWantToUseGoogleMapApiInternals onGoogleApiLoaded={({ map, maps }) => apiIsLoaded(map, maps)} > {renderAddresses()} {renderUsersLocation()} {renderHighlightedUserRoute()} </GoogleMapReact> )
性能优化方案
如果只是修改样式不需要重建圆圈,可以直接调用Circle实例的setOptions方法更新属性,避免销毁重建的性能开销:
useEffect(() => { if (!circlesRef.current.length) return const newStrokeColor = tag.id==='all-jobs'?"orange":'#1aba8b26' circlesRef.current.forEach(circle => { circle.setOptions({ strokeColor: newStrokeColor }) }) }, [tag])
内容的提问来源于stack exchange,提问作者Zusman
相关产品推荐
相关产品推荐

