首页 > 解决方案 > ReactJS 使用 setState() 处理对象数组

问题描述

我在使用 setStates 时遇到问题。我在我的状态中为我的谷歌地图存储了一组标记,我正在使用 for 循环遍历每个标记,以便使用谷歌的地理编码 API 更改标记的位置状态。

这是我的状态:

state = {
    showingInfoWindow: false,  
    activeMarker: {},          
    selectedPlace: {},
    markers: [
      {
        name: "Costco Wholesale",
        address: "9151 Bridgeport Rd, Richmond, BC V6X 3L9",
        position: { lat: 0, lng: 0 },
        placeID: 'ChIJWc2NzuF0hlQRDu0NNhdQCjM'
      } //just trying to get this one to work first before I add in the others
    ],
    busy: []
  };

这是函数(在类中声明):

findLatLong(){
    for(let i = 0; i < this.state.markers.length; i++){
        Geocode.fromAddress(this.state.markers[i].address).then(
            response => {
              const { lati, lngi } = response.results[0].geometry.location;
              this.state.markers[i].position.setState({lat: lati, lng: lngi})
            }
          );
    }
  }

如您所见,我将同一数组元素中包含的地址传递给 .fromAddress 函数,然后使用 setState 将 lat 和 lng 设置为返回值。

我稍后在地图渲染之后但在标记之前调用该函数:

<Map
        google={this.props.google}
        zoom={14}
        style={mapStyles}
        initialCenter={{ lat: 49.166590, lng: -123.133569 }}
      >
      {this.findLatLong}    
      {this.state.markers.map((marker, index) => (
        <Marker
          key={index} 
          onClick={this.onMarkerClick}
          name={marker.name}
          position={marker.position}
        />
      ))}

然而,标记的位置状态并没有改变,而是保持为我在初始状态声明期间传递的填充值。

完整的代码,如果它有帮助:

import React, { Component } from 'react';
import { Map, GoogleApiWrapper, InfoWindow, Marker } from 'google-maps-react';
import Geocode from 'react-geocode';

const key = '';
Geocode.setApiKey(key);

const mapStyles = {
    width: '100%',
    height: '100%'
};

export class MapContainer extends Component {
  state = {
    showingInfoWindow: false,  
    activeMarker: {},          
    selectedPlace: {},
    markers: [
      {
        name: "Costco Wholesale",
        address: "9151 Bridgeport Rd, Richmond, BC V6X 3L9",
        position: { lat: 0, lng: 0 },
        placeID: 'ChIJWc2NzuF0hlQRDu0NNhdQCjM'
      }
    ],
    busy: []
  };

  findLatLong(){
    for(let i = 0; i < this.state.markers.length; i++){
        Geocode.fromAddress(this.state.markers[i].address).then(
            response => {
              const { lati, lngi } = response.results[0].geometry.location;
              this.state.markers[i].position.setState({lat: lati, lng: lngi})
            }
          );
    }
  }

  componentDidMount() {
    this.getList();
  }

  getList = () => {
    fetch('/api/getList')
    .then(res => res.json())
    .then(percent => this.setState({ busy: percent }))
  }

  onMarkerClick = (props, marker, e) =>
  this.setState({
    selectedPlace: props,
    activeMarker: marker,
    showingInfoWindow: true
  });

  onClose = props => {
    if (this.state.showingInfoWindow) {
      this.setState({
        showingInfoWindow: false,
        activeMarker: null
      });
    }
  };

  render() {
    return (
      <Map
        google={this.props.google}
        zoom={14}
        style={mapStyles}
        initialCenter={{ lat: 49.166590, lng: -123.133569 }}
      >
      {this.findLatLong}    
      {this.state.markers.map((marker, index) => (
        <Marker
          key={index} 
          onClick={this.onMarkerClick}
          name={marker.name}
          position={marker.position}
        />
      ))}

        <InfoWindow
          marker={this.state.activeMarker}
          visible={this.state.showingInfoWindow}
          onClose={this.onClose}
        >
          <div>
            <h4>{this.state.selectedPlace.name}</h4>
            <h4>{this.state.busy}</h4>
          </div>
        </InfoWindow>
      </Map>
    );
  }
}

先感谢您!

尝试修复#1

.then(
            response => {
              const { lati, lngi } = response.results[0].geometry.location;
              this.setState(oldState => {
                const newMarkers = [oldState.markers];
                const modifiedMarker = newMarkers[i];
                modifiedMarker.lat = lati;
                modifiedMarker.lng = lngi;
                return {oldState, markers: [newMarkers]};
//How do i implement the modifiedMarkers?
            })

标签: javascriptreactjsgoogle-mapsgoogle-geocoder

解决方案


更新

实际上,最好只改变一次状态而不是在循环内

findLatLong(){
    const newMarkers = [...this.state.markers]
    for(let i = 0; i < this.state.markers.length; i++){
      Geocode.fromAddress(this.state.markers[i].address).then(
        response => {
          const { lati, lngi } = response.results[0].geometry.location;
          newMarkers[i].position.lat = lati; 
          newMarkers[i].position.lng = lngi;
        }
      );
    }

    this.setState(oldState => {
      return { ...oldState, markers: [...newMakers] };
    });
}

这不是你改变状态的方式,它应该是这样的:

    this.setState(oldState => {
      const newMakers = [...oldState.makers];
      const modifiedElement = newMakers[i];
      modifiedElement.lat = lati;
      modifiedElement.lng = lngi;
      return { ...oldState, makers: [...newMakers] };
    });

推荐阅读