与内部的另一个异步 api 调用反应 Native GeoLocation 不起作用

Posted

技术标签:

【中文标题】与内部的另一个异步 api 调用反应 Native GeoLocation 不起作用【英文标题】:ReactNative GeoLocation with another asynchronous api call inside not working 【发布时间】:2017-10-02 22:10:14 【问题描述】:

我正在使用地理定位来获取当前坐标(纬度和经度)。当坐标可用时,我希望能够使用返回的坐标进行 API 调用。 但是,由于某种原因,API 调用没有正确执行。在地理定位返回坐标后立即进行 API 调用的正确方法是什么? 这是代码:

const that = this;
//Getting the current location using the geolocation API
navigator.geolocation.getCurrentPosition(
  (position) => 
    this.setState(
      latitude: position.coords.latitude,
      longitude: position.coords.longitude,
      error: null
    );


 //Here is the API call to be executed after the coordinates are returned and state is set for the latitude and longitude

     const url = 'http://sewoa-easy-breezy-home-number-api-us1.smx.online/api/v1/houses/number?latitude=' + that.state.latitude
       + '&longitude=' + that.state.longitude;
     axios.get(url).then(function (response) 
       if (response.data) 
         Actions.viewHouseNumber( houseNumber: response.data.number );
        else 
         Actions.houseNotFound( latitude: that.state.latitude, longitude: that.state.longitude );
       
     ).catch(() => 
         // The request was made, but the server responded with a status code
         // that falls out of the range of 2xx
         if (that.state.latitude && that.state.longitude) 
           Actions.houseNotFound( latitude: that.state.latitude, longitude: that.state.longitude );
         
         else 
           Actions.error( message: 'connection_error');
         
       );
  ,
(error) => 
Actions.error( message: 'gps_error' );
return;
,
 enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 ,
) 

这里使用的 navigation.getCurrentPostion 和 axios.get 方法都是分开工作的。然而,既然 API 调用在 gelocation.getCurrentPosition 方法中,整个事情就不起作用了。关于如何解决这个问题的任何想法?

【问题讨论】:

【参考方案1】:

在 React 中,setState 是异步的。这意味着它不会立即执行,而是要等到下一个更新周期才能真正执行。这对用户来说通常是不可见的,但这意味着that.state.latitudethat.state.longitude 可能是未定义的。在调用 setState 后立即尝试 console.log(that.state.latitude, that.state.longitude)

解决方案:setState 接受回调作为第二个参数。您可以将依赖于状态新值的所有代码部分放在所述回调中。这将确保在运行这些行之前已更新状态。

这可能看起来像这样(假设您发布的 sn-p 位于组件的 componentWillMount 方法中):

class MyComponent extends Component 
  fetchHouseNumber = () => 
    const url = 'http://sewoa-easy-breezy-home-number-api-us1.smx.online/api/v1/houses/number?latitude=' + this.state.latitude
       + '&longitude=' + this.state.longitude;
    axios.get(url).then(function (response) 
      if (response.data) 
        Actions.viewHouseNumber( houseNumber: response.data.number );
       else 
        Actions.houseNotFound( latitude: this.state.latitude, longitude: this.state.longitude );
      
  

  componentWillMount() 
    //Getting the current location using the geolocation API
    navigator.geolocation.getCurrentPosition(
      (position) => 
        this.setState(
          latitude: position.coords.latitude,
          longitude: position.coords.longitude,
          error: null,
        , () => this.fetchHouseNumber()); // The callback I'm talking about
      
      (error) => 
        Actions.error( message: 'gps_error' );
      ,
      
        enableHighAccuracy: true,
        timeout: 20000,
        maximumAge: 1000
      )
  

旁注:你为什么使用that 而不是这个?由于您使用的是箭头函数,因此您不需要保护this 的值。另外,我没有看到在您的 sn-p 中分配了 that。难道你的问题不是来自这个吗?

编辑:性能

正如 cmets 中所述,在 setState 上使用回调可能会很昂贵。如果您想尽快触发 API 调用,在等待触发 setState 回调之前,您可以这样做:

class MyComponent extends Component 
  fetchHouseNumber = (latitude, longitude) => 
    const url = 'http://sewoa-easy-breezy-home-number-api-us1.smx.online/api/v1/houses/number?latitude=' + latitude
       + '&longitude=' + longitude;
    axios.get(url).then(function (response) 
      if (response.data) 
        Actions.viewHouseNumber( houseNumber: response.data.number );
       else 
        Actions.houseNotFound( latitude, longitude );
      
  

  componentWillMount() 
    //Getting the current location using the geolocation API
    navigator.geolocation.getCurrentPosition(
      (position) => 
        const  latitude, longitude  = position.coords; // destructuring assignment
        this.fetchHouseNumber(latitude, longitude);
        this.setState(
          latitude, // object property shorthand
          longitude,
          error: null
        );
      
      (error) => 
        Actions.error( message: 'gps_error' );
      ,
      
        enableHighAccuracy: true,
        timeout: 20000,
        maximumAge: 1000
      )
  

这样,一旦地理定位数据可用,您就会触发回调,但如果组件中的其他地方需要地理定位数据,您仍然可以将其置于状态(如果不需要,您可以删除 setState 部分...)。

【讨论】:

这是一个我忘记复制的上限范围变量,但我只是对其进行了编辑。在这种情况下,您将如何准确编写 setState 方法(代码方面)? 我刚刚添加了一个sn-p。对不起,我后来发现我的解释很抽象 但是 that 可能不需要,因为您正在使用箭头函数。仅使用 this 并仅声明箭头函数(如果可能)通常比携带 selfthat_this 或在您需要访问回调内部组件的范围时容易得多。 虽然这个答案显示了正确使用setState 的好方法,但您可以只使用position 对象中的值,而不是尝试从状态中读取它们。这将有助于不等待状态设置来进行 API 调用。可能相差几毫秒,但这是另一种思考方式。 @bennygenel 完全正确。我正在编辑 sn-p 考虑到这个性能问题。

以上是关于与内部的另一个异步 api 调用反应 Native GeoLocation 不起作用的主要内容,如果未能解决你的问题,请参考以下文章

反应异步 API 调用

对异步和承诺的困惑。反应原生

React Native API 调用和提取变量

如何取消 useEffect 清理函数中的所有订阅和异步任务?

如何在 api 调用中使用异步等待获取在反应本机中通过基本身份验证

如何在本机反应中调用函数内部的抽屉导航器