I am trying to create a weather app, I am currently stuck on the search bar. I’m working within a component named Inputs.tsx (stores my search bar and buttons to display different temps (F and C)
I was able to display the current location for the weather (right now it is London) but once I hit backspace in the div I immediately get the following error:
Compiled with problems:
×
ERROR
Cannot read properties of undefined (reading ‘name’)
TypeError: Cannot read properties of undefined (reading ‘name’)
I am aware that the value is set to the current default location, but how do I change that once I type another city in and how can I make it display within my App component?
Inputs.tsx
import React, { useEffect, useState } from "react";
import { GrLocation } from "react-icons/gr";
import { AiOutlineSearch } from "react-icons/ai";
function Inputs() {
const [weather, setWeather] = useState<any>();
useEffect(() => {
async function load() {
const weatherData = await getWeather();
setWeather(weatherData);
console.log(weatherData);
}
load();
}, []);
if (!weather) {
return <p>loading</p>;
}
const handleSearch = () => {
if (weather !== "") setWeather({ q: weather });
};
return (
<div>
<div id="search-container">
<AiOutlineSearch onClick={handleSearch} />
<input
id="search-bar"
type="text"
placeholder="Search.."
value={weather.location.name}
onChange={(e) => setWeather(e.currentTarget.value)}
></input>
<GrLocation />
<div className="temperature">
<button name="metric" id="fahrenheit-button">
°F
</button>
<p>|</p>
<button name="imperial" id="celcius-button">
°C
</button>
</div>
</div>
</div>
);
}
async function getWeather() {
const response = await fetch(
"https://api.weatherapi.com/v1/current.json?key=462eaa5d277d46b0957222907232503&q=London&aqi=no"
);
return response.json();
}
export default Inputs;
App.tsx
import { useEffect, useState } from "react";
import { ReactComponent as Logo } from "../src/mag-glass.svg";
import "./App.css";
import Inputs from "./components/Inputs";
import TemperatureAndDetails from "./components/TemperatureAndDetails";
import TimeAndLocation from "./components/TimeAndLocation";
function App() {
const [weather, setWeather] = useState<any>();
useEffect(() => {
async function load() {
const weatherData = await getWeather();
setWeather(weatherData);
console.log(weatherData);
}
load();
}, []);
if (!weather) {
return <p>loading</p>;
}
return (
<div className="App">
<header className="App-header"></header>
<Inputs />
<TimeAndLocation />
<h1>Weather in {weather.location.name}</h1>
<h1 id="temp-display">{weather.current.temp_f}°F</h1>
<TemperatureAndDetails />
<h1>Feels Like: {weather.current.feelslike_f}°F</h1>
<h1>Humidity: {weather.current.humidity}%</h1>
<h1>Wind Speed: {weather.current.gust_mph} mph</h1>
</div>
);
}
async function getWeather() {
const response = await fetch(
"https://api.weatherapi.com/v1/current.json?key=462eaa5d277d46b0957222907232503&q=London&aqi=no"
);
return response.json();
}
export default App;
2
Answers
Use optional chaining (?.) to handle the case when weather.location is undefined:
This will fix the issue for Inputs.
Initialize the weather state with an empty object instead of undefined:
In both cases, you should also update the handleSearch() function to properly set the weather state with the search query, instead of trying to set it directly to an object with a q property:
Just use ternary operator where you drill into
weather
to deal with situation whenweather
is null:{weather ? weather.location.name : ”}