如何在 React Native 中获取 API 之前保存当前位置的经纬度坐标?

Posted

技术标签:

【中文标题】如何在 React Native 中获取 API 之前保存当前位置的经纬度坐标?【英文标题】:How to save the lat, lon coordinates of current location before fetching the API in React Native? 【发布时间】:2019-05-17 04:45:27 【问题描述】:

大家好,

我有一些卡住 Geolocation ,我正在访问我当前的位置以使用我的 Link API 上的纬度和经度,但我遇到了一些无法访问 API 的问题,结果是最初找不到 JSON 数据,当我测试它们时,我保存到单独的变量中但无法正常工作,现在如何在获取 API 之前保存它们?

Error

我的代码在这里:

    import React,  Component  from "react";
    import 
      StyleSheet,
      Text,
      View,
      TextInput,
      ScrollView,
      Image,
      ActivityIndicator
     from "react-native";
    import Icon from "react-native-vector-icons/dist/FontAwesome";


    export default class App extends Component 
      constructor(props) 
        super(props);
        this.state = 
          isLoading: true,
          dataSource: [],
          latitude: null,
          longitude: null,
          error: null
        ;
      
      async componentDidMount() 
        this.watchId = navigator.geolocation.watchPosition(
          position => 
            this.setState(
              latitude: position.coords.latitude,
              longitude: position.coords.longitude,
              error: null
            );
          ,
          error => this.setState( error: error.message ),
          
            enableHighAccuracy: true,
            timeout: 20000,
            maximumAge: 1000,
            distanceFilter: 5
          
        );
    var myLat = `$this.state.latitude`;
        var myLon = `$this.state.longitude`;
     let API_WEATHER = `http://api.openweathermap.org/data/2.5/weather?lat=$myLat&lon=$myLon&units=metric&appid=$API_KEY`;

fetch(API_WEATHER)
      .then(response => response.json())
      .then(responseJson => 
        console.log(responseJson);
        console.log(responseJson.weather);
        this.setState(
          isLoading: false,
          dataSource: responseJson
        );
      )
      .catch(error => 
        console.log(error);
      );
  

render() 
    if (this.state.isLoading) 
      return (
        <View style= flex: 1, padding: 20 >
          <ActivityIndicator size="large" />
        </View>
      );
    
 var icon =
      this.state.dataSource.main.temp <= 20
        ? require("./assets/cloudySun.png")
        : require("./assets/sunny.png");
    return (
      <ScrollView style=styles.container>
        <View style=styles.head>
          <Text style=styles.titleApp>Weather App</Text>
          <View
            style=
              flexGrow: 1,
              alignItems: "center",
              justifyContent: "center"
            
          >
            <Text>Latitude: this.state.latitude</Text>
            <Text>Longitude: this.state.longitude</Text>
            this.state.error ? <Text>Error: this.state.error</Text> : null
          </View>
        </View>
        <View style=styles.defaultWeather>
          <View style=styles.infoDegree>
            <Text style= fontSize: 80, color: "#42434B", paddingBottom: 0 >
              this.state.dataSource.main.temp°
            </Text>
            <Text style= fontSize: 16, padding: 7 >
              this.state.dataSource.name,this.state.dataSource.sys.country
            </Text>
            <Text style= color: "#42434B", fontSize: 20, padding: 2 >
              this.state.dataSource.weather[0].description
            </Text>
          </View>
 var icon =
      this.state.dataSource.main.temp <= 20
        ? require("./assets/cloudySun.png")
        : require("./assets/sunny.png");
    return (
      <ScrollView style=styles.container>
        <View style=styles.head>
          <Text style=styles.titleApp>Weather App</Text>
          <View
            style=
              flexGrow: 1,
              alignItems: "center",
              justifyContent: "center"
            
          >
            <Text>Latitude: this.state.latitude</Text>
            <Text>Longitude: this.state.longitude</Text>
            this.state.error ? <Text>Error: this.state.error</Text> : null
          </View>
        </View>
        <View style=styles.defaultWeather>
          <View style=styles.infoDegree>
            <Text style= fontSize: 80, color: "#42434B", paddingBottom: 0 >
              this.state.dataSource.main.temp°
            </Text>
            <Text style= fontSize: 16, padding: 7 >
              this.state.dataSource.name,this.state.dataSource.sys.country
            </Text>
            <Text style= color: "#42434B", fontSize: 20, padding: 2 >
              this.state.dataSource.weather[0].description
            </Text>
          </View>
         </View>
</ScrollView>



const styles = StyleSheet.create(
  container: 
    flex: 1,
    padding: 5,
    backgroundColor: "#F2F4FA"
  ,
  head: 
    alignItems: "center"
  ,
  titleApp: 
    fontSize: 20,
    fontWeight: "400",
    color: "#000"
  ,
  defaultWeather: 
    flexDirection: "row",
    justifyContent: "space-between"
  ,
  infoDegree: 
    padding: 15,
    marginBottom: 20
  ,
  searchSection: 
    marginBottom: 50,
    flexDirection: "row",
    justifyContent: "center",
    alignItems: "center",
    backgroundColor: "#fff",
    shadowColor: "#eee",
    shadowOffset:  width: 10, height: 3 ,
    shadowOpacity: 0.8,
    shadowRadius: 10,
    elevation: 5
  ,
  searchIcon: 
    padding: 10
  ,
  input: 
    flex: 1,
    paddingTop: 10,
    paddingRight: 10,
    paddingBottom: 10,
    paddingLeft: 0,
    backgroundColor: "#fff",
    color: "#424242"
  ,
  statusWeather: 
    width: 210,
    padding: 20,
    margin: 10,
    backgroundColor: "#e8ebf7"
  ,
  ImgWeek: 
    marginTop: 10,
    marginBottom: 23
  ,
  TextStatus: 
    color: "#607498",
    fontSize: 17,
    padding: 10
  
);

【问题讨论】:

【参考方案1】:

尝试以下,将回调传递给 setState,在那里你会得到新的 lat,long:

  componentDidMount() 
            this.watchId = navigator.geolocation.watchPosition(
              position => 
                this.setState(
                  latitude: position.coords.latitude,
                  longitude: position.coords.longitude,
                  error: null
                ,()=>
        var myLat = `$this.state.latitude`;
            var myLon = `$this.state.longitude`;
         let API_WEATHER = `http://api.openweathermap.org/data/2.5/weather?lat=$myLat&lon=$myLon&units=metric&appid=$API_KEY`;

    fetch(API_WEATHER)
          .then(response => response.json())
          .then(responseJson => 
            console.log(responseJson);
            console.log(responseJson.weather);
            this.setState(
              isLoading: false,
              dataSource: responseJson
            );
          )
          .catch(error => 
            console.log(error);
          );

);
              ,
              error => this.setState( error: error.message ),
              
                enableHighAccuracy: true,
                timeout: 20000,
                maximumAge: 1000,
                distanceFilter: 5
              
            );

      

【讨论】:

我正在尝试,但它需要很长时间没有结果,我现在将在真实设备中尝试它们,但你能向我解释你为什么要传递回调吗?没有回调 setState 有什么不同? setState 是一个异步方法,在将结果实际分配给状态之前需要一些时间,如果您尝试访问状态值,一旦分配操作完成,您传递给 setState 的回调就会被调用在 setState 之后的下一个语句中,您可能会获得以前的值而不是新值。在您的情况下,观察位置本身是异步的,您不知道何时会收到结果,这就是您使用回调的原因,一旦我们获得 lat long 值,我们就会在该回调中执行 fetch 操作(这可能是你的问题的根本原因) 是的,这是正确的人,我运行你的代码,但在我的模拟器中,我知道它需要很长时间,因为它不是正确的位置,但是当我在我的真实手机上运行应用程序时它工作正常但是微调器不工作!相反,在 ُemuolatore 中,有什么想法吗?【参考方案2】:

我对你的代码做了一些性能。我希望这会有所帮助。

import React,  Component  from "react";
import 
  StyleSheet,
  Text,
  View,
  TextInput,
  ScrollView,
  Image,
  ActivityIndicator
 from "react-native";

import Icon from "react-native-vector-icons/dist/FontAwesome";


export default class App extends Component 

  constructor(props) 
    super(props);
    this.ApiKeyRef = 'hdjdjdjjd555555555555'

    this.watchPositionOpts = 
      enableHighAccuracy: true,
      timeout: 20000,
      maximumAge: 1000,
      distanceFilter: 5
    
    this.state = 
      isLoading: true,
      dataSource: [],
      latitude: null,
      longitude: null,
      error: null
    ;
  

  componentDidMount() 
    this.watchId = navigator.geolocation.watchPosition(
      this.watchPositionSuccess, this.watchPositionFail, this.watchPositionOpts 
    );              
       

  componentWillUnmount()
    //dont forget to clear
    navigator.geolocation.clearWatch(this.watchId);
    navigator.geolocation.stopObserving();
             

  watchPositionSuccess = (position) => 
    this.setState( 
      latitude: position.coords.latitude, 
      longitude: position.coords.longitude, 
      error: null
    , () => this.fetchCallback());
  

  watchPositionFail = (err) => 
    this.setState( error: err.message )
  

  fetchCallback = () => 
    const  latitude, longitude  = this.state
    const req = `http://api.openweathermap.org/data/2.5/weather?lat=$latitude&lon=$longitude&units=metric&appid=$this.ApiKeyRef`;
    const callback = (responseJson) => 
      console.log(responseJson)
      console.log(responseJson.weather)
    

    fetch(req)
      .then(response => response.json())
      .then(responseJson => this.setState( isLoading: false, dataSource: responseJson, ()=> callback(responseJson)))
      .catch(error => console.log(error))      
  

  render() 

      const  
        isLoading, 
        dataSource, 
        error, 
        latitude, 
        longitude 
       = this.state; 

      if (isLoading) 
        return (
          <View style= flex: 1, padding: 20 >
            <ActivityIndicator size="large" />
          </View>
        );
      

      const icon = dataSource.main.temp <= 20 ? require("./assets/cloudySun.png") : require("./assets/sunny.png")

      return (
          <ScrollView style=styles.container>
            <View style=styles.head>
              <Text style=styles.titleApp>Weather App</Text>
              <View style= flexGrow: 1, alignItems: "center", justifyContent: "center" >
                <Text>Latitude: latitude</Text>
                <Text>Longitude: longitude</Text>
                error && <Text>Error: error</Text>
              </View>
            </View>
            <View style=styles.defaultWeather>
              <View style=styles.infoDegree>
                <Text style= fontSize: 80, color: "#42434B", paddingBottom: 0 >
                  dataSource.main.temp°
                </Text>
                <Text style= fontSize: 16, padding: 7 >
                  dataSource.name,dataSource.sys.country
                </Text>
                <Text style= color: "#42434B", fontSize: 20, padding: 2 >
                  dataSource.weather[0].description
                </Text>
              </View>
            </View>
          </ScrollView>
      );
    
  

【讨论】:

谢谢你,但我不知道该应用程序不能正常工作,我只显示没有 ActivityIndi​​cator 的白屏!我认为这需要时间? @AnasTe 你能上传一张图片吗? @AnasTe 你也可以发布样式吗? 是的,它需要很长时间才能打开,但我在 if 语句中有一个问题,您可以检查该行是否包含 const icon 当我删除图标行时,它工作正常!错误调用此行无效 const Icon

以上是关于如何在 React Native 中获取 API 之前保存当前位置的经纬度坐标?的主要内容,如果未能解决你的问题,请参考以下文章

如何在reducer中专门使用redux来获取react-native中的API?

如何在 React Native 中获取 API 之前保存当前位置的经纬度坐标?

使用 zoho 图像获取 api 时,如何在 react native 中解决图像数据响应为 null 的问题?

如何从带有条件的 React Native 中的 API 数组结果中获取记录?

React-native Google Drive如何获取文件和文件夹列表?

如何在React Native中使用两个选择器?