HOC中Google Maps Geocode回调内执行this.setState的方法
解决Google Maps Geocode回调中无法调用
this.setState的问题 这个问题的核心原因是普通回调函数里的this指向和React组件实例的this不一致。geocoder.geocode的第二个参数是普通函数,当它被执行时,this的上下文已经不是你的组件实例了,自然无法调用this.setState。
下面给你三种可行的解决方案,按推荐程度排序:
方案1:使用箭头函数作为回调(最简洁,推荐)
箭头函数不会绑定自己的this,它会继承外层作用域的this,也就是你的组件实例。修改代码如下:
onMarkerPositionChanged: (e, reloadList, marker) => { const geocoder = new window.google.maps.Geocoder(); const myLatlng = new window.google.maps.LatLng(e.latLng.lat(), e.latLng.lng()); let dragEndPositions; let nextMarkers; let sitiosNew = []; sessionStorage.id = marker.id; // 把普通回调改成箭头函数,继承外层组件的this geocoder.geocode({'latLng': myLatlng }, (results, status) => { if (status == window.google.maps.GeocoderStatus.OK) { if (results[0]) { dragEndPositions = results[0].formatted_address; console.log(dragEndPositions); nextMarkers = [{ position: myLatlng, nombre: dragEndPositions, icon: icon, direccion: dragEndPositions, latitud: e.latLng.lat(), longitud: e.latLng.lng(), id: sessionStorage.id }]; if(sessionStorage.auto){ JSON.parse(sessionStorage.auto).forEach(nextMarker => { // 修正:nextMarkers是数组,需取第一个元素的id if (nextMarker.id === nextMarkers[0].id) { sitiosNew.push(nextMarkers[0]); } else { sitiosNew.push(nextMarker); } }); } else { // 没有缓存时直接添加当前标记 sitiosNew.push(nextMarkers[0]); } if(sessionStorage.auto){ sessionStorage.removeItem("auto"); } sessionStorage.auto = JSON.stringify(sitiosNew); // 现在this指向组件实例,可正常调用setState this.setState({ markers: sitiosNew }, () => { // 可选:把reloadList放在setState回调里,确保状态更新完成后执行 reloadList(); }); } } }); }
方案2:提前保存组件的this引用
在回调外部把组件的this保存到一个变量(比如that),然后在回调里使用这个变量:
onMarkerPositionChanged: (e, reloadList, marker) => { const geocoder = new window.google.maps.Geocoder(); const myLatlng = new window.google.maps.LatLng(e.latLng.lat(), e.latLng.lng()); let dragEndPositions; let nextMarkers; let sitiosNew = []; sessionStorage.id = marker.id; // 保存组件的this引用 const that = this; geocoder.geocode({'latLng': myLatlng }, function(results, status) { if (status == window.google.maps.GeocoderStatus.OK) { if (results[0]) { // ... 中间逻辑同方案1 ... // 使用that代替this调用setState that.setState({ markers: sitiosNew }, reloadList); } } }); }
方案3:使用bind绑定this到回调函数
通过Function.prototype.bind把回调函数的this强制绑定到组件实例:
onMarkerPositionChanged: (e, reloadList, marker) => { const geocoder = new window.google.maps.Geocoder(); const myLatlng = new window.google.maps.LatLng(e.latLng.lat(), e.latLng.lng()); let dragEndPositions; let nextMarkers; let sitiosNew = []; sessionStorage.id = marker.id; // 使用bind绑定组件的this到回调函数 geocoder.geocode({'latLng': myLatlng }, function(results, status) { if (status == window.google.maps.GeocoderStatus.OK) { if (results[0]) { // ... 中间逻辑同方案1 ... this.setState({ markers: sitiosNew }, reloadList); } } }.bind(this)); // 绑定组件实例的this }
额外注意点
- 原代码里的小问题:
nextMarkers是数组,不能直接用nextMarkers.id,需要取nextMarkers[0].id,我在方案1中已经修正。 this.setState是异步操作,如果reloadList依赖新的状态,最好把它放在setState的第二个回调参数里,确保状态更新完成后再执行。
内容的提问来源于stack exchange,提问作者Erick Vivanco
相关产品推荐
相关产品推荐

