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

React函数组件实现国家-州-城市联动下拉框求助

React + React Bootstrap 实现国家/州/城市联动下拉框问题解决

问题说明

需要基于 React + React Bootstrap 实现国家、州、城市的三级联动下拉框,当前选中国家后无法正确更新州列表,涉及6个状态变量:

  • 选项列表:countries、states、cities
  • 选中项:selectedCountry、selectedState、selectedCity

代码问题分析

  1. setStates调用错误:setStates((prv) => prv, element.states) 写法不符合 React setState 规范,正确的更新方式是直接传入新数组,或通过回调返回新状态。
  2. 遍历效率低下:使用forEach遍历countries匹配选中项,改用find方法可直接定位目标国家,减少不必要的循环。
  3. 状态未重置:切换国家时未重置selectedState和cities,会导致旧的选中状态和城市列表残留。
  4. 逻辑冗余:原代码将选中国家和更新州列表拆分为两个函数,可合并为一个逻辑块,避免依赖异步更新的状态。

修正后的完整代码

App.js

import { useEffect, useState } from 'react';
import RBContainer from './components/RBComponents/container/RBContainer'
import RBSelect from './components/RBComponents/select/RBSelect'
import data from './db.json';
import './App.scss';

function App() {
  const [countries, setCountries] = useState([])
  const [states, setStates] = useState([])
  const [cities, setCities] = useState([])

  const [selectedCountry, setSelectedCountry] = useState("")
  const [selectedState, setSelectedState] = useState("")
  const [selectedCity, setSelectedCity] = useState("")

  // 初始化国家列表
  useEffect(() => {
    setCountries(data)
  }, [])

  // 国家选择变化处理
  const onCountryChangeHandler = (e) => {
    const countryId = parseInt(e.target.value);
    setSelectedCountry(countryId);
    
    // 定位选中国家,更新州列表
    const targetCountry = countries.find(country => country.countryId === countryId);
    setStates(targetCountry ? targetCountry.states : []);
    
    // 重置下级状态
    setSelectedState("");
    setCities([]);
    setSelectedCity("");
  }

  // 州选择变化处理
  const onStateChangeHandler = (e) => {
    const stateId = parseInt(e.target.value);
    setSelectedState(stateId);
    
    // 定位选中州,更新城市列表
    const targetState = states.find(state => state.stateId === stateId);
    setCities(targetState ? targetState.cities : []);
    
    // 重置城市选中状态
    setSelectedCity("");
  }

  // 城市选择变化处理
  const onCityChangeHandler = (e) => {
    setSelectedCity(parseInt(e.target.value));
  }

  return (
    <div className='app my-4'>
      <RBContainer>
        <RBSelect className='mb-4' value={selectedCountry} onChange={onCountryChangeHandler}>
          <option value="" disabled>Select Country</option>
          {countries.map(country => (
            <option
              key={country.countryId}
              value={country.countryId}
            >
              {country.countryName}
            </option>
          ))}
        </RBSelect>

        <RBSelect className='mb-4' value={selectedState} onChange={onStateChangeHandler} disabled={!selectedCountry}>
          <option value="" disabled>Select State</option>
          {states.map(state => (
            <option
              key={state.stateId}
              value={state.stateId}
            >
              {state.stateName}
            </option>
          ))}
        </RBSelect>

        <RBSelect value={selectedCity} onChange={onCityChangeHandler} disabled={!selectedState}>
          <option value="" disabled>Select City</option>
          {cities.map(city => (
            <option
              key={city.cityId}
              value={city.cityId}
            >
              {city.cityName}
            </option>
          ))}
        </RBSelect>
      </RBContainer>
    </div>
  );
}

export default App;

关键修改点

  • 修正setStates调用逻辑,直接传入匹配到的州数组。
  • 用find替代forEach快速定位选中项,提升代码性能。
  • 切换上级选项时自动重置下级选中状态和列表,避免数据残留。
  • 给下级下拉框添加disabled属性,未选中上级时禁止操作,优化用户体验。
  • 调整初始选中状态为空字符串,与选项的value值对应,避免默认选中提示选项的异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 19:51:21