React天气应用中Unsplash API背景图获取问题修复求助
问题修复:React天气应用无限触发API请求及依赖警告问题
问题根源
你的代码中,fetchBackgroundImg和getWeatherType函数会在每次组件渲染时重新创建。如果直接将它们加入useEffect的依赖数组,会导致useEffect反复触发,进而无限调用API;而空依赖数组又会触发React的依赖缺失警告。
修复方案
使用useCallback钩子包裹这两个函数,确保它们的引用在组件生命周期内保持稳定,再将其加入useEffect的依赖数组,即可同时解决无限循环和警告问题。
修改步骤
- 导入
useCallback钩子 - 用
useCallback包裹getWeatherType函数(无依赖,因为它仅依赖传入的参数) - 用
useCallback包裹fetchBackgroundImg函数(依赖为稳定的变量:apiKey、defaultBackgroundImg、setBackgroundImg) - 更新
useEffect的依赖数组,加入稳定后的两个函数
修复后的完整代码
import { useState, useEffect, useCallback } from 'react'; import axios from 'axios'; import Forecast from "./components/Forecast"; import SearchBar from "./components/SearchBar"; import WeeklyForecast from "./components/WeeklyForecast"; import Footer from "./components/Footer"; import './App.css'; // Generate a temperature from -5 to 40 degrees const currentTempGenerated = () => Math.floor(Math.random() * 46) - 5; function App() { const [currentLocation, setCurrentLocation] = useState('London'); function updateLocation(newLocation) { setCurrentLocation(newLocation); } // State variable to store the current temperature const [currentTemp, setCurrentTemp] = useState(0); // Calculate weather type based on current temperature - 用useCallback稳定引用 const getWeatherType = useCallback((temp) => { if (temp >= -5 && temp <= -1) { return 'Snow'; } else if (temp >= 0 && temp <= 3) { return 'Fog'; } else if (temp >= 4 && temp <= 10) { return 'Rain'; } else if (temp >= 11 && temp <= 13) { return 'Drizzle'; } else if (temp >= 14 && temp <= 16) { return 'Clouds'; } else if (temp >= 17 && temp <= 20) { return 'Cloudy'; } else if (temp >= 21 && temp <= 28) { return 'Sunny'; } else if (temp >= 29 && temp <= 31) { return 'Thunder'; } else if (temp >= 32 && temp <= 40) { return 'Heat'; } else { return 'n/a'; } }, []); // 无依赖,函数引用稳定 // State variable to store fetched image URL const [backgroundImg, setBackgroundImg] = useState(null); const apiKey = process.env.REACT_APP_UNSPLASH_API_KEY; // Default image const defaultBackgroundImg = 'https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1170&q=80'; // Fetch image from Unsplash - 用useCallback稳定引用 const fetchBackgroundImg = useCallback(async (weatherType) => { try { const response = await axios.get( `https://api.unsplash.com/photos/random?query=${weatherType}&client_id=${apiKey}` ); const imageURL = response.data.urls.regular; setBackgroundImg(imageURL); } catch (error) { console.error('Error fetching image from Unsplash.com:', error); setBackgroundImg(defaultBackgroundImg); } }, [apiKey, defaultBackgroundImg, setBackgroundImg]); // 依赖均为稳定值 useEffect(() => { const temp = currentTempGenerated(); setCurrentTemp(temp); const weatherType = getWeatherType(temp); fetchBackgroundImg(weatherType); }, [getWeatherType, fetchBackgroundImg]); // 加入稳定后的函数依赖 return ( <div className='container' style={{ backgroundImage: `url(${backgroundImg || defaultBackgroundImg})`, backgroundSize: "cover", backgroundColor: 'rgba(0, 0, 0, 0.8)'}}> <h1 className='logo'>Weatherly</h1> <span className='search-forecast'> <SearchBar updateLocation={updateLocation} /> <Forecast currentTemp={currentTemp} location={currentLocation} /> </span> <WeeklyForecast currentTemp={currentTemp}/> <Footer/> </div> ); } export default App;
说明
useCallback会缓存函数的引用,只有当依赖数组中的变量变化时才会重新创建函数- 这里的依赖数组中的变量都是稳定的(环境变量、常量、useState返回的 setter 函数),因此函数只会在组件初始化时创建一次
useEffect现在只会在组件挂载时执行一次,符合你“仅页面手动刷新时获取一次背景图”的需求,同时消除了依赖警告
内容的提问来源于stack exchange,提问作者NTM17
相关产品推荐
相关产品推荐

