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();
};