Reputation: 501
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
Upvotes: 1
Views: 3715
Reputation: 29314
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));
}, []);
Upvotes: 3
Reputation: 894
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: {}
}
Upvotes: 0