You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免Google Map组件Marker重渲染?仅更新标记位置

解决方案:仅更新Marker位置避免Map组件重渲染

1. 直接通过Marker实例更新位置(最有效)

利用useAdvancedMarkerRef获取Marker的原生实例,当设备位置更新时,直接调用实例的position属性修改位置,无需触发组件重渲染。

在你的CutomMap组件中添加以下useEffect:

useEffect(() => {
  if (!marker) return;
  // 计算新位置
  const newPosition = getMarkerPosition(device, simulatedPosition);
  // 直接更新Marker实例的位置
  marker.position = newPosition;
}, [device, simulatedPosition, marker]);

这样即使CutomMap组件因其他原因重渲染,Marker的位置更新不会触发整个Map的重渲染,而是直接操作Google Maps的原生API修改位置。

2. 用React.memo优化Marker组件

将主设备Marker抽离为独立组件,并使用React.memo包裹,只有当Marker的核心props变化时才重渲染:

创建DeviceMarker.jsx:

import React, { memo } from 'react';
import { AdvancedMarker, useAdvancedMarkerRef, Pin } from '@vis.gl/react-google-maps';
import { getMarkerLabel, getMarkerPosition } from "../utils/mapUtils.js";

const DeviceMarker = memo(({ device, simulatedPosition, onClick }) => {
  const markerPosition = getMarkerPosition(device, simulatedPosition);
  const label = device?.device?.bike?.name;
  const markerLabel = getMarkerLabel(label);
  const [markerRef] = useAdvancedMarkerRef();

  return (
    <AdvancedMarker 
      position={markerPosition} 
      ref={markerRef} 
      title={markerLabel} 
      onClick={onClick}
    >
      <Pin background={'#4611a7'} borderColor={'white'} glyphColor={'white'}>
        {markerLabel}
      </Pin>
    </AdvancedMarker>
  );
});

export default DeviceMarker;

然后在CutomMap中替换原Marker代码:

{shouldShowMarker && (
  <DeviceMarker 
    device={device} 
    simulatedPosition={simulatedPosition} 
    onClick={() => setMarkerInfo(true)} 
  />
)}

3. 优化CutomMap组件的状态与重渲染

  • 将center和zoom从useState改为useMemo,确保设备位置更新时能正确更新,同时避免不必要的状态更新:
import { useMemo } from 'react';

// 替换原有的useState定义
const zoom = useMemo(() => device?.lastLocation ? DEFAULT_ZOOM_IN : DEFAULT_ZOOM_OUT, [device]);
const center = useMemo(() => 
  device?.lastLocation
    ? { lat: device.lastLocation.lat, lng: device.lastLocation.lon }
    : DEFAULT_CENTER, 
[device]);
  • 用React.memo包裹CutomMap组件,避免父组件传递不变的props时触发重渲染:
import { memo } from 'react';

// 替换原有的export语句
export default memo(CutomMap);

4. 优化附近设备Marker的渲染

将附近设备的Marker也抽离为独立组件并使用React.memo,避免nearbyDevices更新时所有Marker都重渲染:

const NearbyDeviceMarker = memo(({ item, mainIMSI }) => {
  const loc = item.device?.location;
  const label = item.device?.bikeName;
  const markerLabel = getMarkerLabel(label);
  const itemId = item.device?.imsi;

  if (!loc?.lat || !loc?.lon || mainIMSI === itemId) return null;

  return (
    <AdvancedMarker
      key={`nearby-${item.device.imsi}`}
      position={{ lat: loc.lat, lng: loc.lon }}
      title={markerLabel}
    >
      <Pin background={'#4611a7'} borderColor={'white'} glyphColor={'black'}>
        {markerLabel}
      </Pin>
    </AdvancedMarker>
  );
});

然后在CutomMap中替换原代码:

{SIMULATION_MODE && nearbyDevices.map((item) => (
  <NearbyDeviceMarker 
    key={`nearby-${item.device.imsi}`} 
    item={item} 
    mainIMSI={device?.device?.imsi} 
  />
))}

关键原因说明

你之前抽离Marker组件未生效,大概率是因为:

  • 未使用React.memo包裹组件,导致父组件重渲染时Marker也跟着重渲染
  • 原组件中center和zoom用useState定义,初始值仅执行一次,设备位置更新时无法正确更新,间接导致Map组件异常重渲染

内容的提问来源于stack exchange,提问作者Hedara Alhasan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 17:24:52