React中如何绑定依赖API数据的联动下拉框默认值?
问题分析与解决方案
核心问题
编辑场景下,formik.values已包含有效的countryId、stateId、cityId,但现有逻辑存在以下缺陷导致State/City下拉无法绑定默认值:
- 依赖
previousCountryId/previousStateId的判断阻止了初始化时自动加载对应层级的选项列表 - 编辑模式下的
useEffect错误地将stateId重置为0,覆盖了从API获取的初始值 - 重复的
useEffect导致逻辑冲突,状态更新混乱
修复后的代码实现
import { useState, useEffect } from 'react'; import { FormikProps } from 'formik'; type TourFormValues = { countryId: number; stateId: number; cityId: number; }; const TourForm = ({ formik, tourId }: { formik: FormikProps<TourFormValues>; tourId?: number }) => { const [countries, setCountries] = useState<any[]>([]); const [states, setStates] = useState<any[]>([]); const [cities, setCities] = useState<any[]>([]); // 获取国家列表 const bindCountries = () => { getAllCountries() .then((res: any) => { setCountries(res.data.status ? res.data.data : []); }) .catch(() => setCountries([])); }; // 根据国家ID获取州列表 const bindStates = (countryId: number) => { if (!countryId) return setStates([]); getStatesByCountry(countryId) .then((res: any) => setStates(res.data.data || [])) .catch(err => console.log(err)); }; // 根据州ID获取城市列表 const bindCities = (stateId: number) => { if (!stateId) return setCities([]); getCitiesByState(stateId) .then((res: any) => setCities(res.data.data || [])) .catch(err => console.log(err)); }; // 初始化加载数据 useEffect(() => { bindCountries(); // 编辑模式下,直接根据初始值加载对应州和城市 if (tourId && formik.values.countryId) { bindStates(formik.values.countryId); if (formik.values.stateId) { bindCities(formik.values.stateId); } } }, [tourId, formik.values.countryId, formik.values.stateId]); // 国家变化时更新州和城市 useEffect(() => { if (formik.values.countryId) { bindStates(formik.values.countryId); // 仅新增模式下重置州和城市选中值 if (!tourId) { formik.setFieldValue('stateId', 0); formik.setFieldValue('cityId', 0); setCities([]); } } else { setStates([]); setCities([]); } }, [formik.values.countryId, tourId]); // 州变化时更新城市 useEffect(() => { if (formik.values.stateId) { bindCities(formik.values.stateId); // 仅新增模式下重置城市选中值 if (!tourId) { formik.setFieldValue('cityId', 0); } } else { setCities([]); } }, [formik.values.stateId, tourId]); return ( <> <FieldSelect className='col-lg-6' isRequired label='Country' name='countryId' formik={formik} > <option value={0}>Select Country</option> {countries.map((item) => ( <option key={item.id} value={item.id}> {item.name} </option> ))} </FieldSelect> <FieldSelect className='col-lg-6' isRequired label='State' name='stateId' formik={formik} > <option value={0}>Select State</option> {states.map((item) => ( <option key={item.id} value={item.id}> {item.name} </option> ))} </FieldSelect> <FieldSelect className='col-lg-6' isRequired label='City' name='cityId' formik={formik} > <option value={0}>Select City</option> {cities.map((item) => ( <option key={item.id} value={item.id}> {item.name} </option> ))} </FieldSelect> </> ); };
关键修复点
- 移除冗余状态:删除
previousCountryId、previousStateId和无用ref,简化依赖逻辑 - 初始化逻辑优化:编辑模式下直接根据Formik初始值加载对应层级的选项列表
- 避免值覆盖:仅在新增模式(无tourId)下重置stateId和cityId,编辑模式保留初始值
- 下拉框绑定简化:FieldSelect通过
name属性与Formik自动绑定,无需手动设置selected或defaultValue
内容的提问来源于stack exchange,提问作者Ashwani Bhardwaj
相关产品推荐
相关产品推荐

