Why does React app fail when I reload page

Viewed 35

I am busy learning javascript, and it, as well as react, nodejs and npm are all brand new concepts to me, so bear with me.

I have managed to piece together an application which returns the weather for my location by following this tutorial: https://www.freecodecamp.org/news/learn-react-by-building-a-weather-app/

I run npm and then I am able to view the executed app on localhost:3000/

When I make changes to the .js application (I use atom), npm compiles the new code and it works perfectly.

But when I reload the web page it doesn't work (returns nothing).

Looking at the console in Chrome, when I do a compile, it immediately gets my location and the API call to openweathermap works (it includes the location in the call of course).

But when I reload the page, it seems like the location is not successfully fetched, and then obviously it cannot return anything. What's weird is that it seems to attempt it 3 times, and the second time it works, but the first and third time it fails.

Here is the piece of code where the issue seems to lie and I also attached an image of what the app looks like when it WORKS, and what the console shows when it does NOT work (when reloading). console when I reload when it works

useEffect(() => {
    const fetchData = async () => {
      navigator.geolocation.getCurrentPosition(function(position) {
        setLat(position.coords.latitude);
        setLong(position.coords.longitude);
      });

      await fetch(`${process.env.REACT_APP_API_URL}/weather/?lat=${lat}&lon=${long}&units=metric&APPID=${process.env.REACT_APP_API_KEY}`)
      .then(res => res.json())
      .then(result => {
        setData(result)
        console.log(d)                      // (GL)
        console.log("Latitude is:", lat)    // (GL)
        console.log("Longitude is:", long)  // (GL)
        console.log(result);
      });
    }
    fetchData();
  }, [lat,long])

2 Answers

You should remove the react-strict wrapper component.

Also - makes no sense writing await fetch when you're using the promise syntax then...

You need so split the logic within the useEffect because you are setting a state within the getCurrentPosition callback, and at the same time listen to a state change in the dependency array of that useEffect...

// this useEffect will only fire when the component mounts (once)
useEffect(() => {
    navigator.geolocation.getCurrentPosition(location => {
        // you should validate the response before setting the state...
        setLat(location.coords.latitude);
        setLong(location.coords.longitude);
    });
}, [])

// this useEffect will be called one the component mounts + when any dependency changes (lat/long)
useEffect(() => {
    fetch(`${process.env.REACT_APP_API_URL}/weather/?lat=${lat}&lon=${long}&units=metric&APPID=${process.env.REACT_APP_API_KEY}`)
        .then(res => res.json())
        .then(result => {
            setData(result)
            console.log(d)                      // (GL)
            console.log("Latitude is:", lat)    // (GL)
            console.log("Longitude is:", long)  // (GL)
            console.log(result);
    });
}, [lat, long])

Even though this is correct, this is considered bad code, and should be split between separate files for dealing with the API/actions/utility methods..etc.

The problem is that your fetchData function is an async function. So when you call fetchData, you'll need a .then() to make sure that it gets the result. Also your useEffect inner function should be async

useEffect(async () => {
    const fetchData = async () => {
      navigator.geolocation.getCurrentPosition(function(position) {
        setLat(position.coords.latitude);
        setLong(position.coords.longitude);
      });

      await fetch(`${process.env.REACT_APP_API_URL}/weather/?lat=${lat}&lon=${long}&units=metric&APPID=${process.env.REACT_APP_API_KEY}`)
      .then(res => res.json())
      .then(result => {
        setData(result)
        console.log(d)                      // (GL)
        console.log("Latitude is:", lat)    // (GL)
        console.log("Longitude is:", long)  // (GL)
        console.log(result);
      });
    }
    fetchData().then(result => {
        //do stuff (or await this fetch data)
    });
  }, [lat,long])

Related