0

I'm trying to load a user's current city onto the page after a call to the Geolocation API. However, the main component where the geolocation function is being called is setting state as undefined before the Promise of location returns.

My goal is to set the state with the user's current location. However, when I'm calling geolocate() in my React component, state.city is being set as undefined because it does not wait for the geolocation function to return anything.

My geolocation functions:

const geolocate = async () => {
    if (!navigator.geolocation) {
        alert('Geolocation is not supported by your browser. Please search for a location to look for weather');
    } else {
        getCoordinates().then((position) => {
            getCityByCoords(position)
            .then((response) => {
                return response;
            })
            .catch(err => console.log(err));
        })
        .catch(err => console.log(err));
    }   
}

const getCoordinates = () => {
    return new Promise((resolve, reject) => {
        navigator.geolocation.getCurrentPosition(
          position => {
            return resolve(position);
          },
          error => reject(error)
        )}
      );
};


// a call to my own API to make a request to Google's geocoding API
// response from this is coming back successfully
const getCityByCoords = (position) => {
    const { latitude, longitude } = position.coords;
    return axios.get('/city', {
        params: {
            lat: latitude,
            lng: longitude
        }
    })
}

The function call in my component:

 componentDidMount() {
    this.getLocation();
  }

  getLocation() {
    geolocate()
    .then(
      (response) => {
        this.setState({
            city: response,
            isLoaded: true
        })
    },
        (error) => {
            this.setState({
              isLoaded: true,
              error
            });
    })
    .then(() => {
      this.setState({ isLoaded: 'false' });
    })
  }

I think all these asynchronous calls are throwing me off.

1 Answer 1

1

First of all, your geolocate function is missing return statements, so you can get the location result in the function call in your component.

Additionally, don't nest Promises, if you can return them. In the following snippet, I've rewritten your geolocate function:

const geolocate = async () => {
  if (!navigator.geolocation) {
    // better would be to throw an error here, so you can handle them in your component (or wherever else)
    alert(
      "Geolocation is not supported by your browser. Please search for a location to look for weather"
    );
  } else {
    // return was missing
    return getCoordinates()
      .then(position => getCityByCoords(position))
      .catch(err => console.log(err));
  }
};

After that, let's tackle your problem: You didn't initialize your state in the constructor, so on the first render, it doesn't know anything about city or isLoaded.

If you put the initialization of your state into your constructor, it should print your desired city, or a simple 'Waiting' paragraph:


class Geo extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      city: "",
      isLoaded: false
    };
  }

  componentDidMount() {
    this.getLocation();
  }

  getLocation() {
    geolocate()
      .then(
        response => {
          this.setState({
            city: response,
            isLoaded: true
          });
        },
        error => {
          this.setState({
            isLoaded: true,
            error
          });
        }
      )
      .then(() => {
        this.setState({ isLoaded: "false" });
      });
  }

  render() {
    if (!this.state.isLoaded) {
      return <div>Waiting for Geolocation...</div>;
    }
    return <div>Geolocation: {this.state.city}</div>;
  }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.