React中setCountry无法更新默认国家下拉选项问题求助
下拉选择框默认值不生效问题解决方法
我需要给下拉选择框设置默认国家选项,选项包括United States、United Kingdom和Rest of the world,对应的可用国家常量如下:
const AVAILABLE_COUNTRIES: PartialDeep<Country[]> = [ { isoCode: 'GB' as CountryCode, name: 'United Kingdom', currency: { isoCode: 'GBP' as CurrencyCode, }, }, { isoCode: 'US' as CountryCode, name: 'United States', currency: { isoCode: 'USD' as CurrencyCode, }, }, ];
当前遇到的问题:页面渲染时下拉框没有默认选中任何值,但直接将const [country, setCountry] = useState('');改为const [country, setCountry] = useState('us');时,下拉框能正常显示United States作为默认选项。
问题原因
useForm的defaultValues仅在组件初始化时生效一次,初始country为空字符串,后续通过useEffect异步获取国家后更新的country状态,无法自动同步到表单中。- 虽然给
FormFieldSelect传了defaultValue={country},但react-hook-form的register方法会接管表单控件状态,defaultValue会被表单初始值覆盖,异步更新的值无法生效。
解决方案
方案一:用react-hook-form的setValue同步异步值
修改useEffect逻辑,在获取到匹配国家后,同时更新组件状态和表单字段值:
const [country, setCountry] = useState(''); const getCountryFromCode = useCallback((code: CountryCode) => { const selected = AVAILABLE_COUNTRIES.find( (country) => country?.isoCode === code.toUpperCase(), ); return selected ? selected.isoCode?.toLowerCase() : 'row'; }, []); const { formState: {errors, isDirty, isSubmitting, isSubmitSuccessful}, handleSubmit, register, setError, setValue, // 新增:获取setValue方法 } = useForm< FormValues & { serverError?: string; } >({ defaultValues: { name: '', email: '', number: '', type: 'trade', country: '', // 初始值设为空或兜底值'row' message: '', }, resolver: yupResolver(schema), }); useEffect(() => { const fetchUserCountry = async () => { try { const response = await fetch('https://ipinfo.io?token=d0f95sdfdsfdsfxxx'); const data = await response.json(); if (data.country) { const userCountry = data.country; const matchingCountry = getCountryFromCode(userCountry); if (matchingCountry) { setCountry(matchingCountry); setValue('country', matchingCountry); // 同步到表单字段 console.log(matchingCountry); } } } catch (error) { console.error('Error occurred while fetching user country:', error); } }; fetchUserCountry(); }, [getCountryFromCode, setValue]); // 把setValue加入依赖数组
方案二:等待国家获取完成后再初始化表单
如果页面允许等待国家信息加载后再渲染表单,可以通过加载状态控制渲染时机:
const [country, setCountry] = useState<string | null>(null); const [isLoading, setIsLoading] = useState(true); const getCountryFromCode = useCallback((code: CountryCode) => { const selected = AVAILABLE_COUNTRIES.find( (country) => country?.isoCode === code.toUpperCase(), ); return selected ? selected.isoCode?.toLowerCase() : 'row'; }, []); useEffect(() => { const fetchUserCountry = async () => { try { const response = await fetch('https://ipinfo.io?token=d0f95sdfdsfdsfxxx'); const data = await response.json(); if (data.country) { const userCountry = data.country; const matchingCountry = getCountryFromCode(userCountry); setCountry(matchingCountry); } else { setCountry('row'); // 无匹配时的兜底默认值 } } catch (error) { console.error('Error occurred while fetching user country:', error); setCountry('row'); // 出错时的兜底默认值 } finally { setIsLoading(false); } }; fetchUserCountry(); }, [getCountryFromCode]); // 等待加载完成后再初始化表单 if (isLoading) { return <div>Loading...</div>; } const { formState: {errors, isDirty, isSubmitting, isSubmitSuccessful}, handleSubmit, register, setError, } = useForm< FormValues & { serverError?: string; } >({ defaultValues: { name: '', email: '', number: '', type: 'trade', country: country!, // 直接使用已获取到的country值 message: '', }, resolver: yupResolver(schema), });
额外注意点
- 检查
FormFieldSelect中的空选项:组件内有一个value=""的禁用选项,若表单字段值为空会选中该选项,确保异步获取的值是gb/us/row中的有效选项值。 - 确认
getCountryFromCode返回值与选项value完全匹配,当前代码中toLowerCase()处理已保证格式一致,无需额外修改。
内容的提问来源于stack exchange,提问作者jerma lover1
相关产品推荐
相关产品推荐

