You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;

关键改动说明:

  1. 状态完全独立:将原有的全局状态拆分为europeXXX和asiaXXX系列,两个区域的状态不再共享
  2. 复用逻辑代码:提取getCityOptions和getWeatherData通用函数,减少重复代码
  3. 优化交互体验:切换国家时自动重置城市选择,未选国家时城市下拉置灰禁用
  4. 增加错误处理:为axios请求添加catch分支,避免请求失败后一直处于加载状态

内容的提问来源于stack exchange,提问作者user11130151

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 10:57:03