useState 不更新变量
useState not update variable
我正在使用 google-map-react
在具有自动建议功能的 google 地图上显示地点,此处示例如下:https://www.freakyjolly.com/google-maps-in-react-example-application。我使用的是 Typescript,所以我的代码与博客不同。
我现在遇到问题:console.log(autoComplete);
在函数 onPlaceChanged
打印 undefined
中。知道为什么会这样吗?我该如何解决?
const AutoComplete = ({map, mapApi, addplace} : {map: any, mapApi: any, addplace: any}) => {
const options = {
// restrict your search to a specific type of result
types: ['address'],
// restrict your search to a specific country, or an array of countries
// componentRestrictions: { country: ['gb', 'us'] },
};
let [searchInput, setSearchInput]= React.useState<HTMLInputElement | null>();
let [autoComplete, setAutoComplete] = React.useState<any>();
React.useEffect(
() => {
const autoCompleteInstance = new mapApi.places.Autocomplete(
searchInput!,
options
);
autoCompleteInstance.addListener('place_changed', onPlaceChanged);
autoCompleteInstance.bindTo('bounds', map);
setAutoComplete(autoCompleteInstance);
console.log(autoCompleteInstance);
// returned function will be called on component unmount
return () => {
mapApi.event.clearInstanceListeners(searchInput!);
}
},
[]
);
const onPlaceChanged = () => {
console.log(autoComplete);
const place : google.maps.places.PlaceResult = autoComplete.getPlace();
if (!place.geometry) return;
if (place.geometry.viewport) {
map.fitBounds(place.geometry.viewport);
} else {
map.setCenter(place.geometry.location);
map.setZoom(17);
}
addplace(place);
searchInput!.blur();
};
const clearSearchBox = () => {
searchInput!.value = '';
}
return (
<div className='relative items-center justify-center w-full p-5 text-center'>
<input
className="w-4/5 text-base"
ref={(ref) => {
searchInput = ref;
}}
type="text"
onFocus={clearSearchBox}
placeholder="Enter a location"
/>
</div>
);
}
问题
console.log(autoComplete);
in function onPlaceChanged
print
undefined. Any idea why this is happening, and how can I fix it?
这是因为您正在关闭回调中的初始未定义 autoComplete
状态。
let [autoComplete, setAutoComplete] = React.useState<any>(); // undefined
...
autoCompleteInstance.addListener('place_changed', onPlaceChanged); // initial "instance"
...
const onPlaceChanged = () => {
console.log(autoComplete); // initial undefined value closed over in scope
...
};
换句话说,您正在访问 autoComplete
状态的陈旧外壳。
解决方案
我建议使用 React 引用来保存 autoCompleteInstance
而不是将其保存在状态中。一个新的 mapApi.places.Autocomplete
实例可以在初始渲染时构造并存储在 ref 中,效果仍然用于添加侦听器并将实例绑定到 map
.
示例:
const autoCompleteInstanceRef = React.useRef<any>(
new mapApi.places.Autocomplete(searchInput!, options)
);
React.useEffect(() => {
autoCompleteInstanceRef.current.addListener('place_changed', onPlaceChanged);
autoCompleteInstanceRef.current.bindTo('bounds', map);
console.log(autoCompleteInstanceRef.current);
// returned function will be called on component unmount
return () => {
mapApi.event.clearInstanceListeners(searchInput!);
};
}, []);
const onPlaceChanged = () => {
console.log(autoCompleteInstanceRef.current);
const place: google.maps.places.PlaceResult = autoCompleteInstanceRef.current.getPlace();
if (!place.geometry) return;
if (place.geometry.viewport) {
map.fitBounds(place.geometry.viewport);
} else {
map.setCenter(place.geometry.location);
map.setZoom(17);
}
addplace(place);
searchInput!.blur();
};
我正在使用 google-map-react
在具有自动建议功能的 google 地图上显示地点,此处示例如下:https://www.freakyjolly.com/google-maps-in-react-example-application。我使用的是 Typescript,所以我的代码与博客不同。
我现在遇到问题:console.log(autoComplete);
在函数 onPlaceChanged
打印 undefined
中。知道为什么会这样吗?我该如何解决?
const AutoComplete = ({map, mapApi, addplace} : {map: any, mapApi: any, addplace: any}) => {
const options = {
// restrict your search to a specific type of result
types: ['address'],
// restrict your search to a specific country, or an array of countries
// componentRestrictions: { country: ['gb', 'us'] },
};
let [searchInput, setSearchInput]= React.useState<HTMLInputElement | null>();
let [autoComplete, setAutoComplete] = React.useState<any>();
React.useEffect(
() => {
const autoCompleteInstance = new mapApi.places.Autocomplete(
searchInput!,
options
);
autoCompleteInstance.addListener('place_changed', onPlaceChanged);
autoCompleteInstance.bindTo('bounds', map);
setAutoComplete(autoCompleteInstance);
console.log(autoCompleteInstance);
// returned function will be called on component unmount
return () => {
mapApi.event.clearInstanceListeners(searchInput!);
}
},
[]
);
const onPlaceChanged = () => {
console.log(autoComplete);
const place : google.maps.places.PlaceResult = autoComplete.getPlace();
if (!place.geometry) return;
if (place.geometry.viewport) {
map.fitBounds(place.geometry.viewport);
} else {
map.setCenter(place.geometry.location);
map.setZoom(17);
}
addplace(place);
searchInput!.blur();
};
const clearSearchBox = () => {
searchInput!.value = '';
}
return (
<div className='relative items-center justify-center w-full p-5 text-center'>
<input
className="w-4/5 text-base"
ref={(ref) => {
searchInput = ref;
}}
type="text"
onFocus={clearSearchBox}
placeholder="Enter a location"
/>
</div>
);
}
问题
console.log(autoComplete);
in functiononPlaceChanged
print undefined. Any idea why this is happening, and how can I fix it?
这是因为您正在关闭回调中的初始未定义 autoComplete
状态。
let [autoComplete, setAutoComplete] = React.useState<any>(); // undefined
...
autoCompleteInstance.addListener('place_changed', onPlaceChanged); // initial "instance"
...
const onPlaceChanged = () => {
console.log(autoComplete); // initial undefined value closed over in scope
...
};
换句话说,您正在访问 autoComplete
状态的陈旧外壳。
解决方案
我建议使用 React 引用来保存 autoCompleteInstance
而不是将其保存在状态中。一个新的 mapApi.places.Autocomplete
实例可以在初始渲染时构造并存储在 ref 中,效果仍然用于添加侦听器并将实例绑定到 map
.
示例:
const autoCompleteInstanceRef = React.useRef<any>(
new mapApi.places.Autocomplete(searchInput!, options)
);
React.useEffect(() => {
autoCompleteInstanceRef.current.addListener('place_changed', onPlaceChanged);
autoCompleteInstanceRef.current.bindTo('bounds', map);
console.log(autoCompleteInstanceRef.current);
// returned function will be called on component unmount
return () => {
mapApi.event.clearInstanceListeners(searchInput!);
};
}, []);
const onPlaceChanged = () => {
console.log(autoCompleteInstanceRef.current);
const place: google.maps.places.PlaceResult = autoCompleteInstanceRef.current.getPlace();
if (!place.geometry) return;
if (place.geometry.viewport) {
map.fitBounds(place.geometry.viewport);
} else {
map.setCenter(place.geometry.location);
map.setZoom(17);
}
addplace(place);
searchInput!.blur();
};