React双级联下拉列表联动冲突:如何实现独立互不影响?
解决React中两个区域级联下拉列表相互干扰的问题
你的问题核心在于所有状态都是全局共享的:selected、value、city、weatherData这些变量同时被欧洲和亚洲两个区域使用,导致操作其中一个下拉时,另一个的状态也被同步修改。要解决这个问题,需要把状态按区域拆分,让每个区域拥有独立的状态和逻辑。
具体解决方案步骤:
- 拆分独立状态:为欧洲、亚洲分别声明专属的选中国家、选中城市、天气数据等状态,确保两者互不影响
- 重构事件处理:每个区域的下拉操作只修改自身对应的状态
- 独立生成选项:根据各自区域选中的国家,生成对应的城市下拉列表
- 分离天气逻辑:每个区域独立触发天气请求、存储和展示数据
修改后的完整代码:
import { useState, useEffect } from 'react'; import axios from 'axios'; function DisplayDifferentLocation({ searchCities }) { // 欧洲区独立状态 const [europeSelectedCountry, setEuropeSelectedCountry] = useState(""); const [europeSelectedCity, setEuropeSelectedCity] = useState("No City"); const [europeWeatherData, setEuropeWeatherData] = useState(null); const [isEuropeLoading, setIsEuropeLoading] = useState(false); // 亚洲区独立状态 const [asiaSelectedCountry, setAsiaSelectedCountry] = useState(""); const [asiaSelectedCity, setAsiaSelectedCity] = useState("No City"); const [asiaWeatherData, setAsiaWeatherData] = useState(null); const [isAsiaLoading, setIsAsiaLoading] = useState(false); // 通用天气请求函数 const getWeatherData = (selectedCity, setWeatherData, setLoading) => { if (selectedCity && selectedCity !== "No City" && selectedCity !== "Choose City") { setLoading(true); const url = `https://api.openweathermap.org/data/2.5/weather?q=${selectedCity}&units=metric&appid=08acd577f8ab8cabf637f7cd3736a629`; axios.get(url) .then((response) => { setWeatherData(response.data); setLoading(false); }) .catch(err => { console.error(err); setLoading(false); }); } }; // 欧洲区国家选择处理 const handleEuropeCountryChange = (event) => { setEuropeSelectedCountry(event.target.value); setEuropeSelectedCity("Choose City"); }; // 欧洲区城市选择处理 const handleEuropeCityChange = (event) => { setEuropeSelectedCity(event.target.value); }; // 亚洲区国家选择处理 const handleAsiaCountryChange = (event) => { setAsiaSelectedCountry(event.target.value); setAsiaSelectedCity("Choose City"); }; // 亚洲区城市选择处理 const handleAsiaCityChange = (event) => { setAsiaSelectedCity(event.target.value); }; // 欧洲区天气请求副作用 useEffect(() => { getWeatherData(europeSelectedCity, setEuropeWeatherData, setIsEuropeLoading); }, [europeSelectedCity]); // 亚洲区天气请求副作用 useEffect(() => { getWeatherData(asiaSelectedCity, setAsiaWeatherData, setIsAsiaLoading); }, [asiaSelectedCity]); // 根据国家生成城市选项的通用函数 const getCityOptions = (country) => { const cityLists = { UK: ["Choose City", "London", "Manchester", "Birmingham", "Glasgow"], France: ["Choose City", "Paris", "Calais", "Lyon", "Nice"], Spain: ["Choose City", "Barcelona", "Madrid", "Córdoba", "Seville "], China: ["Choose City", "Beijing", "Shanghai", "Hong Kong", "Macau"], India: ["Choose City", "Delhi", "Chennai", "Madras", "Luknow"], Kazakhstan: ["Choose City", "Astana", "Almaty", "Shymkent", "Atau"] }; const cities = cityLists[country] || []; return cities.map(city => <option key={city}>{city}</option>); }; const handleSubmit = (event) => { event.preventDefault(); }; if (isEuropeLoading || isAsiaLoading) { return <h2>加载中,请稍候</h2>; } return ( <form onSubmit={handleSubmit}> <div className="page"> <div className="europe"> <ul> <p style={{ fontSize: 32 }}>Europe</p> <select onChange={handleEuropeCountryChange}> <option>Choose Country</option> <option>UK</option> <option>France</option> <option>Spain</option> </select> <p> <select name="city" value={europeSelectedCity} onChange={handleEuropeCityChange} disabled={!europeSelectedCountry} > {getCityOptions(europeSelectedCountry)} </select> </p> <p className="city"> City:{` ${europeSelectedCity}`}</p> <br /> {europeWeatherData && ( <> <p>Humidity: {europeWeatherData.main.humidity}</p> <p>Temp: {europeWeatherData.main.temp}</p> <p>Feels Like: {europeWeatherData.main.feels_like}</p> <p>Wind: {europeWeatherData.wind.speed}</p> </> )} </ul> </div> <div className="asia"> <ul> <p style={{ fontSize: 32 }}>Asia</p> <select onChange={handleAsiaCountryChange}> <option>Choose Country</option> <option>China</option> <option>India</option> <option>Kazakhstan</option> </select> <p> <select name="city2" value={asiaSelectedCity} onChange={handleAsiaCityChange} disabled={!asiaSelectedCountry} > {getCityOptions(asiaSelectedCountry)} </select> </p> <p className="city2"> City:{` ${asiaSelectedCity}`}</p> <br /> {asiaWeatherData && ( <> <p>Humidity: {asiaWeatherData.main.humidity}</p> <p>Temp: {asiaWeatherData.main.temp}</p> <p>Feels Like: {asiaWeatherData.main.feels_like}</p> <p>Wind: {asiaWeatherData.wind.speed}</p> </> )} </ul> </div> </div> </form> ); } export default DisplayDifferentLocation;
关键改动说明:
- 状态完全独立:将原有的全局状态拆分为
europeXXX和asiaXXX系列,两个区域的状态不再共享 - 复用逻辑代码:提取
getCityOptions和getWeatherData通用函数,减少重复代码 - 优化交互体验:切换国家时自动重置城市选择,未选国家时城市下拉置灰禁用
- 增加错误处理:为axios请求添加catch分支,避免请求失败后一直处于加载状态
内容的提问来源于stack exchange,提问作者user11130151
相关产品推荐
相关产品推荐

