React Native中如何将REST API获取的经纬度存入useState实现动态导航
可落地的React Native 地址转坐标导航实现方案
一、先清理不兼容的状态写法
直接把之前混用的类组件语法全部移除,函数组件下所有状态统一用useState定义,每个状态的结构如下:
- 起点地址输入值:存储用户在输入框输入的起点文本
- 终点地址输入值:存储用户输入的终点文本
- 起点坐标:存储地理编码解析得到的起点经纬度
- 终点坐标:存储地理编码解析得到的终点经纬度
- 加载状态:控制按钮禁用,避免重复提交请求
正确的定义示例:
import { useState } from 'react' // 组件内直接编写,不需要绑定this const [startAddress, setStartAddress] = useState('') const [endAddress, setEndAddress] = useState('') // 可以把之前测试通过的硬编码坐标作为初始值 const [startCoords, setStartCoords] = useState({ latitude: 39.9042, longitude: 116.4074 }) const [endCoords, setEndCoords] = useState({ latitude: 31.2304, longitude: 121.4737 }) const [isLoading, setIsLoading] = useState(false)
你之前觉得“useState定义坐标时未暴露更新方法”,本质是写的时候漏了解构useState返回数组的第二个值——useState的返回值固定是[当前状态值, 更新状态的函数],比如上面定义startCoords的时候,第二个解构出来的setStartCoords就是专门用来更新起点坐标的方法,不需要额外绑定,直接可以在组件内任意位置调用。
二、修正TextInput的事件绑定
之前输入事件绑定不对,大概率是混淆了类组件的事件绑定逻辑,函数组件下的TextInput不需要通过this绑定方法,直接把输入文本同步到状态即可,正确写法:
<TextInput placeholder="请输入起点地址" value={startAddress} // 直接把输入框拿到的文本传给对应的更新方法,不需要额外传参逻辑 onChangeText={(text) => setStartAddress(text)} style={{ borderWidth: 1, padding: 8, marginVertical: 8 }} /> <TextInput placeholder="请输入终点地址" value={endAddress} onChangeText={(text) => setEndAddress(text)} style={{ borderWidth: 1, padding: 8, marginVertical: 8 }} />
注意:不要把输入值的更新逻辑写在按钮的点击事件里,TextInput的文本变化必须通过onChangeText回调同步到状态,不然用户输入的文本根本无法被后续逻辑获取。
三、对接地理编码API,正确写入坐标状态
把你已经写好的Google地理编码请求逻辑封装成通用方法,拿到返回的经纬度后,直接调用之前解构出来的坐标更新方法赋值,完全不需要用类组件的this.setState,示例代码:
// 封装地理编码请求,传入地址字符串,返回标准化的坐标对象 const fetchGeoCode = async (address) => { // 替换成你已经写好的Google地理编码请求逻辑 const response = await fetch(`已配置的Google地理编码接口地址&address=${encodeURIComponent(address)}`) const result = await response.json() // 从接口返回结构里取到经纬度,转成数字类型(避免接口返回字符串导致地图渲染异常) const location = result.results[0].geometry.location return { latitude: Number(location.lat), longitude: Number(location.lng) } } // 点击按钮触发生成路线 const onGenerateRoutePress = async () => { setIsLoading(true) try { // 并行请求起点、终点的坐标,减少等待时间 const [startLocation, endLocation] = await Promise.all([ fetchGeoCode(startAddress), fetchGeoCode(endAddress) ]) // 直接调用之前的坐标更新方法赋值,没有任何上下文绑定问题 setStartCoords(startLocation) setEndCoords(endLocation) } catch (error) { console.log('地址解析失败,请检查输入内容或接口配置', error) } finally { setIsLoading(false) } }
最后把地图组件的起点、终点props绑定到对应的状态值即可:
<MapView {/* 原有地图配置保持不变 */} region={{ ...startCoords, latitudeDelta: 0.01, longitudeDelta: 0.01 }} > <MapView.Marker coordinate={startCoords} title="起点" /> <MapView.Marker coordinate={endCoords} title="终点" /> {/* 原有路线渲染逻辑保持不变,因为坐标已经是最新的状态值 */} </MapView> <Button title={isLoading ? '路线生成中...' : '生成导航路线'} onPress={onGenerateRoutePress} disabled={isLoading} />
四、容易踩的细节坑
- 绝对不要在函数组件里写
this.state.xxx或者this.setState()的语法,函数组件没有类组件的实例this上下文,写了只会抛出undefined错误 - 不要直接修改状态的值,比如不要写
startCoords.latitude = 123这种代码,必须通过setStartCoords({...})传入全新的对象更新状态,不然组件不会触发重渲染 - 接口请求拿到的经纬度一定要做Number类型转换,部分接口返回的经纬度是字符串,会导致地图定位偏移、路线不渲染的问题
内容的提问来源于stack exchange,提问作者Evans
相关产品推荐
相关产品推荐

