1

I'm struggling to get my data from a fetch request into the state of my container

My fetch request is stored in api.js and looks like this - it retrieves the key from a constant which is fine:-

import { openWeatherKey } from './constants';

const getWeather = async() => {
    const base = "https://api.openweathermap.org/data/2.5/onecall";
    const query = `?lat=52.6&lon=-2.2&exclude=hourly,daily&appid=${openWeatherKey}`;

    const response = await fetch(base + query);
    const data = await response.json();

    return data;
}

export { getWeather };

My container looks like this:-

import React, { Component } from "react";
import './weather.css';
import { getWeather } from './api';

class Spy extends Component {

    constructor() {
        super()
        this.state = {test(){return "this is a test"}}
    }

    render() {
        return (
            <div id="spy-weather" className="app-border">
                <h3 className="spy-name">Weather at { this.props.location } {this.state.test()}</h3> 
            </div>
        )
    }
}

(() => {
    getWeather().then(data => {
        console.log(data);  
    })
})();  

export { Spy as Weather };

I have an IIFE which makes the request and prints the results to the console. You can see that between the class declaration and the export statement above.

Here are the results from the console - the request works fine

{lat: 52.6, lon: -2.2, timezone: "Europe/London", timezone_offset: 3600, current: {…}}
current: {dt: 1594401262, sunrise: 1594353486, sunset: 1594412995, temp: 289.05, feels_like: 286.49, …}
lat: 52.6
lon: -2.2
timezone: "Europe/London"
timezone_offset: 3600
__proto__: Object

What I can't manage to do is set the state with the data from the resolved promise. I've tried various things, including some solutions I've seen which didn't work.

How do I place and run the function within the container and then update state with the data?

I'm pretty new to React as you can probably tell.

With sincere thanks,

Phil

blake
  • 180
  • 9

2 Answers2

1

In class based components, lifecycle method known as componentDidMount is used to do something after component has mounted. In your case, move the code in IIFE in the componentDidMount method.

Make a property in state object which will hold the weather data. Optionally, you can also make a property in state object to hold any error message that might occur during the fetching of data from the API.

this.state = {
   weatherData: null,
   error: ''
};

and then call getWeather() function from componentDidMount() lifecycle method

componentDidMount() {
    getWeather()
      .then(data => {
        this.setState({ weatherData: data });
      })
      .catch(error => this.setState({ error: error.message }));
}

In functional components, useEffect hook is used to perform any side-effect like fetching data from an API. State in functional components is saved using useState hook.

If you use a functional component, then your code will look like this:

const [weatherData, setWeatherData] = useState(null);
const [error, setError] = useState(null);

useEffect(() => {
    getWeather()
      .then(data => {
          setWeatherData(data);
      })
      .catch(error => setError(error.message));
}, []);
Yousaf
  • 20,803
  • 4
  • 23
  • 45
  • I want to thank you for the time you've taken to answer the question; snippets of code and explanations. That's brilliant. I'll need some time to digest this and try and get my app working but will be happy to accept the answer once I get back on Monday and get the thing working! Have a great weekend and thanks again – blake Jul 10 '20 at 20:34
  • thank you very much, I can confirm it worked. Answer accepted. All the best, Phil – blake Jul 13 '20 at 10:29
0
this.state = {test(){return "this is a test"}}

This is invalid structure for state managment, right way

getWeather().then(data => {
        console.log(data);
        this.setState({ weatherData: data });
})

state structure too

state = {
  someProperty: value,
  someArray: [],
  weatherData: {}
}
Nijat Aliyev
  • 292
  • 1
  • 9