3

I have tried this a variety of different ways but am getting stumped. New to using promises and making api calls in react. This is what I have at the moment:

import React, { Component } from 'react'
import Column from './Column'
import { CardGroup } from 'reactstrap';

let api = "https://fcc-weather-api.glitch.me/api/current?";


class App extends Component {

    constructor(props) {
        super(props)
        this.state = {
            isLoaded: false,
            items: {},
        }

    this.fetchWeather = this.fetchWeather.bind(this)
}

fetchWeather(apiStr) {
    fetch(apiStr)
        .then(res => res.json())
        .then(

            (result) => {

                console.log(result)
                this.setState({
                    isLoaded: true,
                    items: result.main
                });
                console.log(this.state);
            },
            // Note: it's important to handle errors here
            // instead of a catch() block so that we don't swallow
            // exceptions from actual bugs in components.
            (error) => {
                this.setState({
                    isLoaded: true,
                    error
                });
            }
        )

}

componentDidMount() {
    if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(function (position) {
            api += `lat=${position.coords.latitude}&lon=${position.coords.longitude}`;     
        })
        this.fetchWeather(api);
    }
}

Right now the api call is being executed before getting the current position. I have tried various ways and havn't been able to access the current position before the fetch executes. Whats the best way to handle this? Any insights on this would be really appreciated. Any questions, let me know.Thanks.

Alex Kramer
  • 33
  • 1
  • 1
  • 3

2 Answers2

7

Since getting the location is done with a callback you must fetch inside the callback

navigator.geolocation.getCurrentPosition((position) => {
  api += `lat=${position.coords.latitude}&lon=${position.coords.longitude}`;
  this.fetchWeather(api);
});
João Cunha
  • 9,929
  • 4
  • 40
  • 61
  • When I do that I get `Uncaught TypeError: Cannot read property 'fetchWeather' of null` at `this.fetchWeather(api)` – Alex Kramer Aug 21 '18 at 15:52
  • @AlexKramer sorry didn't see you used function. Gonna edit. Arrow functions allow you to use the this keyword without binding it – João Cunha Aug 21 '18 at 15:53
4

What about using hook like usePosition() and functional component?

In this case the task of fetching data after browser location is detected may look like this:

import React, { useEffect } from 'react';
import { usePosition } from 'use-position';

export const Weather = () => {
  const { latitude, longitude, error } = usePosition();

  useEffect(() => {
    if (latitude && longitude && !error) {
      // Fetch weather data here.
    }
  }, []);

  return <div>Render weather data here</div>;
};

And of course don't forget about installing the custom hook using npm:

npm i use-position --save

or using yarn:

yarn add use-position
Oleksii Trekhleb
  • 2,543
  • 20
  • 22
  • looks good! love the simplicity of this approach instead of using `navigator.geolocation` directly – Konrad Jul 07 '20 at 09:31
  • there's also `react-geolocated` but I don't find the usage elegant. – Konrad Jul 07 '20 at 09:37
  • [React Hooks vs. Wrapper Hell—Writing State in a Function with Ease](https://www.polidea.com/blog/react-hooks-vs-wrapper-hell-writing-state-in-a-function-with-ease/) – Konrad Jul 07 '20 at 09:45