React TypeScript天气应用搜索栏报错:无法读取undefined的'name'属性
天气应用搜索栏报错与数据更新问题解决
错误原因
- Inputs组件中,
weather状态被同时用来存储API返回的天气对象和搜索框的字符串值。当按下退格键时,setWeather(e.currentTarget.value)把weather变成了字符串,此时再访问weather.location.name自然会抛出Cannot read properties of undefined (reading 'name')错误。 - App和Inputs组件各自维护独立的
weather状态,导致搜索后的数据无法同步到App组件展示。
修复后的代码
App.tsx
将天气状态统一在App组件管理,提供更新天气的方法给Inputs组件,移除重复的getWeather函数:
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>(); const [loading, setLoading] = useState(true); // 统一获取天气数据的函数 async function getWeather(city: string = "London") { setLoading(true); try { const response = await fetch( `https://api.weatherapi.com/v1/current.json?key=462eaa5d277d46b0957222907232503&q=${city}&aqi=no` ); const data = await response.json(); setWeather(data); } catch (err) { console.error("获取天气失败:", err); } finally { setLoading(false); } } useEffect(() => { getWeather(); }, []); if (loading) { return <p>loading</p>; } return ( <div className="App"> <header className="App-header"></header> {/* 把getWeather传递给Inputs,用于搜索新城市 */} <Inputs onSearch={getWeather} currentCity={weather.location.name} /> <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> ); } export default App;
Inputs.tsx
单独维护搜索输入框的状态,不再复用weather对象,通过props接收父组件的搜索方法和当前城市:
import React, { useState } from "react"; import { GrLocation } from "react-icons/gr"; import { AiOutlineSearch } from "react-icons/ai"; // 定义props类型 type InputsProps = { onSearch: (city: string) => void; currentCity: string; }; function Inputs({ onSearch, currentCity }: InputsProps) { const [searchQuery, setSearchQuery] = useState(currentCity); const handleSearch = () => { if (searchQuery.trim()) { onSearch(searchQuery.trim()); } }; // 按回车键触发搜索 const handleKeyPress = (e: React.KeyboardEvent<HTMLInputElement>) => { if (e.key === "Enter") { handleSearch(); } }; return ( <div> <div id="search-container"> <AiOutlineSearch onClick={handleSearch} /> <input id="search-bar" type="text" placeholder="Search.." value={searchQuery} onChange={(e) => setSearchQuery(e.currentTarget.value)} onKeyPress={handleKeyPress} /> <GrLocation /> <div className="temperature"> <button name="imperial" id="fahrenheit-button"> °F </button> <p>|</p> <button name="metric" id="celcius-button"> °C </button> </div> </div> </div> ); } export default Inputs;
关键改进点
- 状态提升:把天气数据的状态统一放在App组件管理,Inputs组件只负责搜索输入和触发搜索,避免状态分散导致的数据不同步。
- 分离状态职责:Inputs组件用
searchQuery专门存储输入框的值,不再混用API返回的对象,彻底解决退格时的类型错误。 - 统一数据获取:把
getWeather函数放在App组件,通过props传递给Inputs,确保搜索新城市后能更新App的天气状态,从而展示新数据。 - 增加错误处理:在
getWeather中加入try/catch,处理网络请求失败的情况。 - 优化交互:增加回车键触发搜索的功能,提升用户体验。
内容的提问来源于stack exchange,提问作者Dilek
相关产品推荐
相关产品推荐

