You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

react-native-google-places-autocomplete报错:request has not been opened求助

react-native-google-places-autocomplete 偶发报错:request has not been opened

问题描述

点击react-native-google-places-autocomplete组件的列表项时,偶发request has not been opened错误,导致应用崩溃,有时能正常运行。已查阅官方文档及仓库Issues,使用组件提供的onFail方法未捕获到任何错误信息。

错误截图

request has not been opened 错误截图

代码实现

import React, { useEffect, useRef, useState } from 'react'
import { ActivityIndicator, Image, Modal, StyleSheet, Text, TouchableOpacity, View } from 'react-native'
import MapView, { Callout, Marker, PROVIDER_GOOGLE } from 'react-native-maps';
import colors from '../theme/colors'
import { appConstants, extraConstants } from '../utils/constants';
import { SubmitButton } from './Button';
import { responsiveHeight, responsiveWidth } from '../utils/responsive_Dimensions';
import { NavigationHeader } from './Header';
import images from '../theme/images';
import { useDispatch, useSelector } from 'react-redux';
import { getGeoCodeAddress, getUserCurrentLocation } from '../utils/commonMethods';
import { GooglePlacesAutocomplete } from 'react-native-google-places-autocomplete';
import { setUserLocation } from '../store/slice/userSlice';

const MapModal = ({ onExit, onSubmit }: any) => {
    const mapref = useRef<any>()
    const googleAutocompleteRef = useRef<any>()
    const userLocation: any = useSelector((state: any) => state?.userReducer.userLocation);
    const dispatch = useDispatch()
    const [pinLocation, setPinLocation] = useState({ latitude: 0, longitude: 0 })
    const [fetchingCurrentLocation, setFetchingCurrentLocation] = useState(false)
    const [isFetchingAddress, setIsFetchingAddress] = useState(false)
    const [initialRegion, setInitialRegion] = useState({
        latitude: 0,
        longitude: 0,
        latitudeDelta: 0.08,
        longitudeDelta: 0.08,
    })

    useEffect(() => {
        setPinLocation({ latitude: userLocation.lat, longitude: userLocation.lng })
        setInitialRegion((prevData: any) => { return { ...prevData, latitude: userLocation.lat, longitude: userLocation.lng } })
    }, [])
    const onDragEnd = async (event: any) => {
        let coordinates = event.nativeEvent.coordinate
        setPinLocation(coordinates)
    }
    const _onSubmit = async () => {
        let geoAddress: any = await getGeoCodeAddress({ lat: pinLocation.latitude, lng: pinLocation.longitude })
        dispatch(setUserLocation({
            lat: pinLocation.latitude,
            lng: pinLocation.longitude,
            geoAddress: geoAddress
        }))
        setTimeout(() => {
            setIsFetchingAddress(false)
            onExit()
        }, 300);
    }
    const animateToRegion = (latitude: any, longitude: any) => {
        mapref?.current?.animateToRegion({ latitude, longitude, latitudeDelta: 0.08, longitudeDelta: 0.08 }, 3000)
    }

    const setCurrentLocation = () => {
        setFetchingCurrentLocation(true)
        getUserCurrentLocation().then((myLocation: any) => { animateToRegion(myLocation?.lat, myLocation?.lng) }).finally(() => { setFetchingCurrentLocation(false) })
    }
    const GooglePlacesAutocompleteCrossButton = () => {
        return (
            <TouchableOpacity style={styles.googlePlacesAutocompleteCrossButton} onPress={() => {
                googleAutocompleteRef?.current?.setAddressText("")
                googleAutocompleteRef?.current?.clear()
            }}>
                <Image source={images.close} style={styles.googlePlacesAutocompleteCrossIcon} />
            </TouchableOpacity>
        )
    }
    return (
        <Modal
            visible={true}
            animationType='slide'
            onRequestClose={onExit}>
            <View style={styles.container}>
                <View style={styles.googlePlacesAutocomplete}>
                    <GooglePlacesAutocomplete
                        placeholder={appConstants?.searchLocation}
                        ref={googleAutocompleteRef}
                        renderRightButton={() => <GooglePlacesAutocompleteCrossButton />}
                        fetchDetails={true}
                        onPress={(data, details: any = null) => {
                            let { lat, lng } = details?.geometry?.location
                            lat && lng && animateToRegion(lat, lng)
                        }}
                        onFail={(err) => { console.log("GooglePlacesAutocomplete - error -> ", err); }}
                        query={{ key: extraConstants.myApiKey, language: 'en', }}
                    />
                </View>
                <NavigationHeader
                    isFloating={true}
                    onBackPress={onExit}
                    title={appConstants.selectLocation}
                />
                {initialRegion.latitude != 0 && initialRegion.longitude != 0 && <MapView
                    style={styles.mapContainer}
                    ref={mapref}
                    onRegionChange={(coords) => {
                        googleAutocompleteRef?.current?.blur()
                        setPinLocation({ latitude: coords.latitude, longitude: coords.longitude })
                    }}
                    initialRegion={initialRegion}>
                    <Marker coordinate={pinLocation} draggable={true} onDragEnd={onDragEnd} pinColor='red' />
                </MapView>}
                <SubmitButton
                    isLoading={isFetchingAddress}
                    style={styles.submitButton}
                    activeOpacity={1}
                    title={appConstants.submit}
                    onPressIn={() => {
                        setIsFetchingAddress(true)
                    }}
                    onPress={onSubmit
                        ? async () => {
                            let geoAddress: any = await getGeoCodeAddress({ lat: pinLocation.latitude, lng: pinLocation.longitude })
                            onSubmit({
                                lat: pinLocation.latitude,
                                lng: pinLocation.longitude,
                                geoAddress: geoAddress
                            })
                            setTimeout(() => {
                                setIsFetchingAddress(false)
                            }, 300);
                        }
                        : _onSubmit}
                />
                <TouchableOpacity style={styles.myLocationBtn} activeOpacity={0.9} onPress={setCurrentLocation}>
                    {
                        fetchingCurrentLocation
                            ? (<ActivityIndicator style={styles.myLocationIcon} color={colors.mainTheme} />)
                            : (<Image source={images.myLocation} style={styles.myLocationIcon} />)
                    }
                </TouchableOpacity>
            </View>
        </Modal >
    )
}

export default MapModal

可能的解决方案

  • 添加异常捕获与参数校验:在onPress回调中增加try-catch和参数判断,避免无效数据导致的异常:
    onPress={(data, details: any = null) => {
      try {
        if (!details?.geometry?.location) return;
        const { lat, lng } = details.geometry.location;
        animateToRegion(lat, lng);
      } catch (err) {
        console.error('GooglePlacesAutocomplete onPress异常:', err);
      }
    }}
    
  • 调整地图区域变化时的模糊时机:避免在请求过程中强制模糊打断请求,增加延迟:
    onRegionChange={(coords) => {
      setPinLocation({ latitude: coords.latitude, longitude: coords.longitude });
      setTimeout(() => {
        googleAutocompleteRef?.current?.blur();
      }, 500);
    }}
    
  • 添加请求防抖:给GooglePlacesAutocomplete组件添加debounce={300}属性,减少频繁请求引发的异常
  • 监听Modal状态:在Modal的visible状态变化时,重置自动补全组件的状态,避免组件未就绪时触发请求

内容的提问来源于stack exchange,提问作者Harpreet Singh - React Native

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 16:42:34