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

React.js中Google Maps的infowindow.close()无法调用求助

问题:React Google Maps项目中调用infowindow.close()时报错“不是函数”

问题描述

我在React.js的Google Maps项目里,infowindow.open()功能正常,但在filter函数中调用infowindow.close()时,一直报错“infowindow.close() is not a function”。请问如何在filter函数中调用componentDidMount内创建的infowindow?

我的代码片段:

export default class MapContainer extends Component {
  constructor(props) {
    super(props)
    this.state = {
      places: [],
      filtered: [],
      search: ''
    }
  }

  componentDidMount() {
    if (this.props && this.props.google) {
      const { google, infowindow } = this.props;
      const maps = google.maps;
      const mapRef = this.refs.map;
      const node = ReactDOM.findDOMNode(mapRef);
      const mapConfig = Object.assign({}, {
        center: { lat: 51.0486, lng: -114.0708 },
        zoom: 11,
        mapTypeId: 'roadmap'
      })
      this.map = new maps.Map(node, mapConfig);

      zomatoAPI()
        .then(p => {
          this.setState({ places: p, filtered: p })
          const { google, infowindow } = this.props;
          p.forEach(location => {
            location.marker = new google.maps.Marker({
              position: { lat: Number(location.location.latitude), lng: Number(location.location.longitude) },
              map: this.map,
              title: location.name
            });
            location.marker.addListener('click', function () {
              const content = `<div class="place"> 
                <img height= 70px width=70px src=${this.photo} alt="${this.title}">
                <h3>${this.title}</h3>
                <p>Cuisine: ${this.cuisines}</p>
                <p>Rating: ${this.rateText}, ${this.rating}</p>
                <p>Price: ${this.price}</p>
                `
              const infowindow = new google.maps.InfoWindow()
              infowindow.setContent(content)
              infowindow.open(this.map, this)
            })
          })
        })
    }
  }

  filter = (e) => {
    const { google, infowindow } = this.props
    const { places, filtered } = this.state;
    const search = e.target.value;
    this.setState({ search: search })
    infowindow.close() // >>>> 这里报错!
  }
}

问题根源

你遇到的问题主要有两个核心原因:

  1. 局部infowindow实例无法被外部访问:你在marker的click事件回调里创建了一个局部的infowindow变量,这个实例只存在于回调函数内部,组件的filter函数根本访问不到它。
  2. props中的infowindow未初始化:你在filter函数里尝试从props获取infowindow,但你的代码里并没有把创建好的infowindow传递给组件props,所以这个值是undefined,自然调用close()会报错。

解决方案

我们需要把infowindow变成组件级的实例属性,让整个组件的方法都能访问到同一个infowindow实例,具体步骤如下:

1. 在componentDidMount中创建全局infowindow实例

把infowindow保存到this.infowindow(组件实例的属性),而不是在click事件里局部创建:

componentDidMount() {
  if (this.props && this.props.google) {
    const { google } = this.props;
    const maps = google.maps;
    const mapRef = this.refs.map;
    const node = ReactDOM.findDOMNode(mapRef);
    const mapConfig = Object.assign({}, {
      center: { lat: 51.0486, lng: -114.0708 },
      zoom: 11,
      mapTypeId: 'roadmap'
    })
    this.map = new maps.Map(node, mapConfig);

    // 关键:创建组件级的infowindow实例,保存到this上
    this.infowindow = new maps.InfoWindow();

    zomatoAPI()
      .then(p => {
        this.setState({ places: p, filtered: p })
        p.forEach(location => {
          location.marker = new google.maps.Marker({
            position: { lat: Number(location.location.latitude), lng: Number(location.location.longitude) },
            map: this.map,
            title: location.name
          });
          // 用箭头函数保持this指向组件实例,而不是marker
          location.marker.addListener('click', () => {
            const content = `
              <div class="place">
                <img height="70px" width="70px" src="${location.photo}" alt="${location.name}">
                <h3>${location.name}</h3>
                <p>Cuisine: ${location.cuisines}</p>
                <p>Rating: ${location.rateText}, ${location.rating}</p>
                <p>Price: ${location.price}</p>
              </div>
            `;
            // 使用组件实例的infowindow
            this.infowindow.setContent(content);
            this.infowindow.open(this.map, location.marker);
          });
        });
      });
  }
}

2. 修改filter函数,调用组件实例的infowindow.close()

现在filter函数可以直接访问this.infowindow,调用它的close方法:

filter = (e) => {
  const { places } = this.state;
  const search = e.target.value.toLowerCase();

  // 先关闭infowindow,加判断避免初始化前调用报错
  if (this.infowindow) {
    this.infowindow.close();
  }

  // 处理过滤逻辑(优化:直接基于原始places数组过滤)
  const filtered = places.filter(place => 
    place.name.toLowerCase().includes(search)
  );

  this.setState({ search, filtered });
}

为什么这样能解决问题?

  • 把infowindow保存到this.infowindow后,整个组件的所有方法都能访问到同一个实例,不会出现局部变量无法访问的问题。
  • 使用箭头函数作为marker的click回调,确保this指向组件实例,而不是marker对象,这样能正确调用this.infowindow。
  • 增加了if (this.infowindow)的判断,避免在组件还没完成初始化时调用close方法导致的错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:43:37