Reputation: 399
I am trying to fetch data from OpenWeatherMap by searching. the data shows like this:
{
"coord": {
"lon": 77.22,
"lat": 28.67
},
"weather": [
{
"id": 711,
"main": "Smoke",
"description": "smoke",
"icon": "50d"
}
],
"base": "stations",
"main": {
"temp": 286.45,
"feels_like": 283.95,
"temp_min": 283.15,
"temp_max": 289.82,
"pressure": 1020,
"humidity": 66
},
"visibility": 1200,
"wind": {
"speed": 2.6,
"deg": 290
},
"clouds": {
"all": 0
},
"dt": 1609221695,
"sys": {
"type": 1,
"id": 9165,
"country": "IN",
"sunrise": 1609206186,
"sunset": 1609243383
},
"timezone": 19800,
"id": 1273294,
"name": "Delhi",
"cod": 200
}
for example if I wanna show the name and date time of the city by data.name and data.dt I can do that but in case of showing country name India by data.sys.country, It shows me the error: can't destructure property country as it is undefined. How to fix that?
Code:
const [search, setSearch] = useState("");
const [weatherData, setWeatherData] = useState({});
useEffect(() => {
const getData = async () => {
try {
setLoading(true);
const response = await axios.get(
"https://api.openweathermap.org/data/2.5/weather?appid=your_api_key&q=" +
search
);
setWeatherData(response.data);
setLoading(false);
} catch (error) {
setLoading(false);
}
};
getData();
}, [search]);
const { name, dt } = weatherData;
const { country } = weatherData.sys;
return (
<>
<div>
<input
className="form-control w-50"
type="text"
onBlur={(e) => setSearch(e.target.value)}
placeholder="search products"
/>
<button>Search</button>
</div>
<div>
<h2>City Name: {name} </h2>
<h3>Country: {country}</h3>
</div>
</>
);
Upvotes: 0
Views: 1264
Reputation: 10665
Link to working app: Stackblitz, just use correct the API keys.
Initially, the weatherData
sate is empty, so when you try to access the values on the first render cycle you will get that error as Axios is still working on getting the data from the server, to avoid that, you can use either conditional rendering or null propagation (?.)
operator:
Full example:
import React, { useState, useEffect } from "react";
import axios from "axios";
import "./style.css";
const API_KEY = "your API key";
export default function App() {
const [search, setSearch] = useState("pune");
const [weatherData, setWeatherData] = useState({});
const [loading, setLoading] = useState(false);
const getData = () => {
setLoading(true);
axios
.get(
`https://api.openweathermap.org/data/2.5/weather?appid=${API_KEY}&q=${search}`
)
.then(response => {
setWeatherData(response.data);
setLoading(false);
})
.catch(error => {
setLoading(false);
console.log("error", error);
});
};
useEffect(() => {
getData();
}, [search]);
// also remove it๐, you are trying to destructure those elements which are not present initially so they will throw an error.
//const { name, dt } = weatherData;
//const { country } = weatherData?.sys;
return (
<>
<div>
<input
className="form-control w-50"
type="text"
onBlur={e => setSearch(e.target.value)}
placeholder="search products"
/>
<button onClick={getData}>Search</button>
</div>
<div>
<h2>City Name: {weatherData?.name} </h2>
<h3>Country: {weatherData?.sys?.country}</h3>
<h2>DT : {weatherData?.dt} </h2>
</div>
</>
);
}
I will prefer the above approach.
Another solution is to store the initial value in the state, but if you have lot of values to deal with then this approach is not advisable.
Full example:
const [weatherData, setWeatherData] = useState({
name: "",
dt: "",
sys: { country: "" }
});
Full Example:
import React, { useState, useEffect } from "react";
import axios from "axios";
import "./style.css";
const API_KEY = "your API key";
export default function App() {
const [search, setSearch] = useState("pune");
const [weatherData, setWeatherData] = useState({
name: "",
dt: "",
sys: { country: "" }
});
const [loading, setLoading] = useState(false);
const getData = () => {
setLoading(true);
axios
.get(
`https://api.openweathermap.org/data/2.5/weather?appid=${API_KEY}&q=${search}`
)
.then(response => {
setWeatherData(response.data);
setLoading(false);
})
.catch(error => {
setLoading(false);
console.log("error", error);
});
};
useEffect(() => {
getData();
}, [search]);
const { name, dt } = weatherData;
const { country } = weatherData.sys;
return (
<>
<div>
<input
className="form-control w-50"
type="text"
onBlur={e => setSearch(e.target.value)}
placeholder="search products"
/>
<button onClick={getData}>Search</button>
</div>
<div>
<h2>City Name: {name} </h2>
<h3>Country: {country}</h3>
<h3>DT: {dt}</h3>
</div>
</>
);
}
Upvotes: 1