React函数组件实现国家-州-城市联动下拉框求助
React + React Bootstrap 实现国家/州/城市联动下拉框问题解决
问题说明
需要基于 React + React Bootstrap 实现国家、州、城市的三级联动下拉框,当前选中国家后无法正确更新州列表,涉及6个状态变量:
- 选项列表:
countries、states、cities - 选中项:
selectedCountry、selectedState、selectedCity
代码问题分析
- setStates调用错误:
setStates((prv) => prv, element.states)写法不符合 React setState 规范,正确的更新方式是直接传入新数组,或通过回调返回新状态。 - 遍历效率低下:使用
forEach遍历countries匹配选中项,改用find方法可直接定位目标国家,减少不必要的循环。 - 状态未重置:切换国家时未重置
selectedState和cities,会导致旧的选中状态和城市列表残留。 - 逻辑冗余:原代码将选中国家和更新州列表拆分为两个函数,可合并为一个逻辑块,避免依赖异步更新的状态。
修正后的完整代码
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
相关产品推荐
相关产品推荐

