我正在用ReactJS制作附近的餐馆应用。我正在通过搜索输入使用Google地方信息自动填充功能。我正在尝试进行地理位置定位,似乎运行顺利。
出问题的是,每当我在自动完成下拉列表中选择一个位置时,我都会运行一个传递查询字符串以转换为地理位置的函数,我的搜索结果始终呈现以前的经度和纬度状态,而不是在该函数的最后一次运行中获取的那个。
我似乎无法正确执行这些命令的执行顺序。
我正在谈论的功能如下:
handlePlaceSelect = () => {
// Extract City From Address Object
const addressObject = this.autocomplete.getPlace();
const address = addressObject.address_components;
const URL = `https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=${
this.state.lat
},${this.state.lng}&type=restaurant&radius=${5 *
1000}&key=MYAPIKEY`;
Geocode.setApiKey('MYAPIKEY');
// Check if address is valid
if (address) {
// Set State
this.setState({
city: address[0].long_name,
query: addressObject.formatted_address
});
}
Geocode.fromAddress(this.state.query)
.then(
response => {
const { lat, lng } = response.results[0].geometry.location;
this.setState({
lat: lat,
lng: lng
});
},
error => {
console.error(error);
}
)
.then(
axios
.get(URL)
.then(response => {
console.log(response.data);
this.setState({ places: response.data.results });
})
.catch(error => {
console.log(error.message);
})
);
};
这是此组件的其余代码:
import React, { Component } from 'react';
// Imports
import axios from 'axios';
import Script from 'react-load-script';
import { Button, SearchInput } from 'evergreen-ui';
import ResultsItem from '../../components/ResultsItem/ResultsItem.jsx';
import Geocode from 'react-geocode';
// Styles
import './Search.scss';
class Autocomplete extends Component {
// Define Constructor
constructor(props) {
super(props);
// Declare State
this.state = {
type: 'restaurant',
radius: 10,
lat: '59.0738',
lng: '41.3226',
city: '',
query: '',
open: false,
places: []
};
this.currentLocationOnClick = this.currentLocationOnClick.bind(this);
this.handlePlaceSelect = this.handlePlaceSelect.bind(this);
}
currentLocationOnClick() {
navigator.geolocation.getCurrentPosition(
position => {
this.setState({ lat: position.coords.latitude });
this.setState({ lng: position.coords.longitude });
},
error => {
console.log('Error getting location');
}
);
}
async componentDidMount() {
const url = `https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=
${this.state.lat},${this.state.lng}type=restaurant&radius=${2 *
1000}&key=MYAPIKEY`;
const response = await fetch(url);
const data = await response.json();
this.setState({ places: data.results });
console.log(data.results);
}
handleScriptLoad = () => {
// Declare Options For Autocomplete
const options = {
types: ['address']
}; // To disable any eslint 'google not defined' errors
// Initialize Google Autocomplete
/*global google*/ this.autocomplete = new google.maps.places.Autocomplete(
document.getElementById('autocomplete'),
options
);
// Avoid paying for data that you don't need by restricting the set of
// place fields that are returned to just the address components and formatted
// address.
this.autocomplete.setFields(['address_components', 'formatted_address']);
// Fire Event when a suggested name is selected
this.autocomplete.addListener('place_changed', this.handlePlaceSelect);
};
handlePlaceSelect = () => {
// Extract City From Address Object
const addressObject = this.autocomplete.getPlace();
const address = addressObject.address_components;
const URL = `https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=${
this.state.lat
},${this.state.lng}&type=restaurant&radius=${5 *
1000}&key=MYAPIKEY`;
Geocode.setApiKey('MAAPIKEY');
// Check if address is valid
if (address) {
// Set State
this.setState({
city: address[0].long_name,
query: addressObject.formatted_address
});
}
Geocode.fromAddress(this.state.query)
.then(
response => {
const { lat, lng } = response.results[0].geometry.location;
this.setState({
lat: lat,
lng: lng
});
},
error => {
console.error(error);
}
)
.then(
axios
.get(URL)
.then(response => {
console.log(response.data);
this.setState({ places: response.data.results });
})
.catch(error => {
console.log(error.message);
})
);
};
render() {
const findPlacesOnClick = () => {
const URL = `https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=${
this.state.lat
},${this.state.lng}&type=restaurant&radius=${5 *
1000}&key=MYAPIKEY`;
axios
.get(URL)
.then(response => {
console.log(response.data);
this.setState({ places: response.data.results });
})
.catch(error => {
console.log(error.message);
});
};
return (
<div>
<div className="search">
<SearchInput
id="autocomplete"
placeholder="Search by address"
width="100%"
height={56}
/>
<Button onClick={this.currentLocationOnClick}>
{this.state.lat} & {this.state.lng}
</Button>
<Button appearance="primary" onClick={findPlacesOnClick}>
Fetch
</Button>
<Script
url="https://maps.googleapis.com/maps/api/js?key=MYAPIKEY&libraries=places,geometry&callback=initAutocomplete"
onLoad={this.handleScriptLoad}
/>
</div>
<div className="results">
{this.state.places.map(places => (
<div className="results-item" onClick={this.props.sideBarOpen}>
<ResultsItem name={places.name} />
</div>
))}
</div>
</div>
);
}
}
export default Autocomplete;
答案 0 :(得分:0)
setState
函数可以是异步。在下一次渲染之前,this.state
对象很可能不会使用传递给this.setState
的对象进行更新。
解决方法是将要发生的事情放在状态更改后的中在回调中:
this.setState({
city: address[0].long_name,
query: addressObject.formatted_address
}, state => {
// the rest of the code
});
...或仅坚持原子状态更改。如果您不需要在两个setState
调用之间重新渲染,则首选此方法:
handlePlaceSelect = async () => {
let { query } = this.state;
// Extract City From Address Object
const addressObject = this.autocomplete.getPlace();
const address = addressObject.address_components;
Geocode.setApiKey('MYAPIKEY');
// Check if address is valid
let city;
if (address) {
city = address[0].long_name;
query = addressObject.formatted_address
}
let lat, lng;
try {
const response = await Geocode.fromAddress(query);
({ lat, lng } = response.results[0].geometry.location);
} catch (error) {
console.error(error);
}
let places;
try {
const URL = `https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=${lat},${lng}&type=restaurant&radius=${5 * 1000}&key=MYAPIKEY`;
const response = await axios.get(URL)
console.log(response.data);
places = response.data.results;
} catch (err) {
console.log(error.message);
}
this.setState({ query, places, city, lat, lng });
}