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

React替换Yandex Maps Placemark图标时触发removeChild空指针错误

解决React Yandex地图切换Placemark图标时的DOM操作错误

错误原因

你写的代码里犯了几个典型的React使用错误:

  • 直接通过document.getElementById操作DOM,不仅不符合React状态驱动的设计思想,还可能因为Yandex Maps组件的DOM结构和你预期不符,导致获取到null,触发Cannot read properties of null错误。
  • IconGeoPosition是普通变量,不是React状态,修改它不会触发组件重新渲染,就算DOM操作成功,图标也不会更新。
  • elem.removeChild(elem)逻辑错误,removeChild方法需要传入当前元素的子元素,不能传入元素本身,正确写法应该是元素的父元素调用removeChild(elem)。

正确解决方案

用React状态来控制Placemark的图标地址,完全抛弃手动DOM操作,这才是React的正确打开方式。修改后的完整代码如下:

import React, { useState, useEffect, useMemo } from "react";
import './SearchPower.css';
import { YMaps, Map, Placemark} from '@pbe/react-yandex-maps';

function App() {
  // 定义地理位置状态
  const [lat, setLat] = useState(0);
  const [lng, setLng] = useState(0);
  // 定义图标地址状态
  const [iconGeoPosition, setIconGeoPosition] = useState("images/Marks/ZemMark.png");

  // 获取用户地理位置,用useEffect确保只执行一次
  useEffect(() => {
    navigator.geolocation.getCurrentPosition((position) => {
      setLat(position.coords.latitude);
      setLng(position.coords.longitude);
    }, () => {
      // 定位失败时使用默认坐标
      setLat(55.75);
      setLng(37.57);
    });
  }, []);

  // 处理默认坐标(当lat和lng都为0时使用默认值)
  const currentLat = lat === 0 && lng === 0 ? 55.75 : lat;
  const currentLng = lat === 0 && lng === 0 ? 37.57 : lng;

  // 创建地图配置,用useMemo依赖currentLat和currentLng
  const myMap = useMemo(
    () => ({ center: [currentLat, currentLng], zoom: 9 }),
    [currentLat, currentLng]
  );

  // 切换图标函数,直接更新状态
  function geoPositionMarkChanged(linkMark) {
    setIconGeoPosition(linkMark);
  }
  
  return (
    <div className="ContextSP">
      <div className="DivMarks">
        <img 
          className="MarkLeftImage" 
          src="images/Marks/ZemMark.png" 
          onClick={() => geoPositionMarkChanged("images/Marks/ZemMark.png")}
        />
        <img 
          className="MarkImage" 
          src="images/Marks/Redcar1Mark.png" 
          onClick={() => geoPositionMarkChanged("images/Marks/Redcar1Mark.png")}
        />
        <img 
          className="MarkImage" 
          src="images/Marks/Redcar2Mark.png" 
          onClick={() => geoPositionMarkChanged("images/Marks/Redcar2Mark.png")}
        />
        <img 
          className="MarkImage" 
          src="images/Marks/GreencarMark.png" 
          onClick={() => geoPositionMarkChanged("images/Marks/GreencarMark.png")}
        />
        <img 
          className="MarkRightImage" 
          src="images/Marks/YellowcarMark.png" 
          onClick={() => geoPositionMarkChanged("images/Marks/YellowcarMark.png")}
        />
      </div>
      <YMaps>
        <Map style={{width: '100%', height: '100%', margin: '0 0 10px 0'}} state={myMap}>
          <Placemark 
            geometry={[currentLat, currentLng]} 
            options={{
              iconLayout: 'default#image',
              iconImageHref: iconGeoPosition,
              iconImageSize: [40, 40],
              iconImageOffset: [100, -10]
            }} 
          />
        </Map>
      </YMaps>
    </div>
  )
}

export default App;

关键改动说明

  1. 状态化图标地址:用useState定义iconGeoPosition,每次点击图片调用setIconGeoPosition更新状态,React会自动重新渲染Placemark,实现图标切换。
  2. 优化定位逻辑:用useEffect包裹定位代码,依赖项为空数组确保组件挂载时只执行一次定位;同时添加定位失败回调,更优雅处理默认坐标。
  3. 移除DOM操作:完全删掉手动删除、创建Placemark的代码,让React负责UI更新,彻底避免DOM操作带来的错误。
  4. 改进默认坐标处理:用currentLat和currentLng变量代替直接修改状态值,避免渲染时修改状态引发的问题。

内容的提问来源于stack exchange,提问作者Виктор

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 18:32:28