React Hooks天气应用出现Too many re-renders无限循环错误的技术求助
Hey there! Let's break down why you're hitting that frustrating error and get your weather app working smoothly with Hooks.
What's Causing the Infinite Re-Renders?
The problem is right here in your component's top-level code:
if (info.weather) { switch (info.weather[0].main) { // ... your case statements calling setBackground } }
Every time your component renders (which happens every time you update state, like when setInfo runs after the API call), this block executes. Calling setBackground updates state, which triggers another render... which runs this block again, and so on. It's an infinite loop!
The Fix: Use useEffect for State-Dependent Updates
We need to move that background-switching logic into a useEffect hook. This hook lets us run code only when specific dependencies change, instead of on every render.
Here's how to adjust your code:
- First, add
useEffectto your React imports:
import React, { useState, useEffect } from "react";
- Replace your top-level
if/switchblock with thisuseEffect:
useEffect(() => { if (info.weather) { switch (info.weather[0].main) { case "Rain": setBackground("rain"); break; case "Clouds": setBackground("clouds"); break; case "Snow": setBackground("snow"); break; case "Fog": setBackground("fog"); break; case "Drizzle": setBackground("drizzle"); break; // Fixed missing break here! case "Thunderstorm": setBackground("thunderstorm"); break; // Fixed missing break here too! case "Clear": setBackground("app"); break; default: setBackground("app"); // Add a default to handle unexpected weather types } } }, [info]); // Only run this effect when `info` changes
Notice I also fixed missing break statements in your switch cases—without those, a "Drizzle" weather type would fall through to the "Thunderstorm" case and overwrite your background setting!
Full Modified Code
Here's your complete app code with all fixes applied:
import React, { useState, useEffect } from "react"; import axios from "axios"; import "./App.css"; const dateBuilder = (today) => { let months = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ]; let days = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", ]; let day = days[today.getDay()]; let date = today.getDate(); let month = months[today.getMonth()]; return `${day} ${date} ${month}`; }; const key = process.env.REACT_APP_WEATHER_API_KEY; const App = () => { const [info, setInfo] = useState([]); const [background, setBackground] = useState("app"); const handleInputChange = (event) => { if (event.key === "Enter") { const city = event.target.value; const apiUrl = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${key}`; axios .get(apiUrl) .then((res) => { const { data } = res; setInfo(data); }) .catch((err) => console.log("err", err)); } }; useEffect(() => { if (info.weather) { switch (info.weather[0].main) { case "Rain": setBackground("rain"); break; case "Clouds": setBackground("clouds"); break; case "Snow": setBackground("snow"); break; case "Fog": setBackground("fog"); break; case "Drizzle": setBackground("drizzle"); break; case "Thunderstorm": setBackground("thunderstorm"); break; case "Clear": setBackground("app"); break; default: setBackground("app"); } } }, [info]); return ( <div className={background}> <main> <div className="search-box"> <input type="text" className="search-bar" placeholder="search..." onKeyPress={handleInputChange} /> </div> <div className="location-box"> <div className="location">{info.name}</div> <div className="date">{dateBuilder(new Date())}</div> </div> {typeof info.main != "undefined" ? ( <div> <div className="weather-box"> <div className="temp"> {Math.round(info.main.temp - 273.15)}º C </div> <div className="weather">{info.weather[0].main}</div> <div className="pressure">{info.main.pressure} mbar</div> <div className="humidity">{info.main.humidity} % humidity</div> {/* Fixed duplicate class name here too! */} </div> </div> ) : ( <></> )} </main> </div> ); }; export default App;
Quick Notes
- I also fixed a duplicate
pressureclass name on your humidity element—small detail, but it'll keep your CSS working as expected. - Remember: never call state setters (like
setBackgroundorsetInfo) directly in the component's top-level render code. Always useuseEffectfor updates that depend on other state/props.
内容的提问来源于stack exchange,提问作者cypher

