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() // >>>> 这里报错! } }
问题根源
你遇到的问题主要有两个核心原因:
- 局部infowindow实例无法被外部访问:你在marker的click事件回调里创建了一个局部的infowindow变量,这个实例只存在于回调函数内部,组件的filter函数根本访问不到它。
- 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
相关产品推荐
相关产品推荐

