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

如何让MUI Autocomplete提交时返回国家ID而非名称?

问题:MUI Autocomplete 结合 react-hook-form 提交时获取国家ID而非名称

我使用MUI的Autocomplete组件开发表单,结合react-hook-form处理提交,但提交后console输出的是国家名称,而我需要的是国家ID。后端返回的国家数据结构为:{"id":1,"country":"United Kingdom","symbol":"uk"}。尝试用onChange配合setValue修改表单值,但没生效,想实现类似普通select组件那样,显示名称但提交ID的效果。

原代码如下:

const Profile = () => {
  const {
    register,
    handleSubmit,
    setValue,
    formState: { errors },
  } = useForm({});

  const [countries, setCountries] = useState([]);

  const submit = async (value) => {
    console.log(value);
    console.log(value.countries);
  };

  useEffect(() => {
    axios.get("get-countries").then((data) => {
      setCountries(data.data);
    });
  }, []);

  return (
    <>
      <form method="post" onSubmit={handleSubmit(submit)}>
        {categories.countries && (
          <Autocomplete
            id="country-select-demo"
            options={categories.countries}
            autoHighlight
            getOptionLabel={(option) => option.country}
            renderOption={(props, option) => (
              <Box
                component="li"
                sx={{ "& > img": { mr: 2, flexShrink: 0 } }}
                {...props}
              >
                <img
                  loading="lazy"
                  width="20"
                  src={`https://flagcdn.com/w20/${option.symbol.toLowerCase()}.png`}
                  srcSet={`https://flagcdn.com/w40/${option.symbol.toLowerCase()}.png 2x`}
                  alt=""
                />
                {option.country}
              </Box>
            )}
            renderInput={(params) => (
              <TextField
                {...params}
                label="Country"
                inputProps={{
                  ...params.inputProps,
                  autoComplete: "country",
                }}
                {...register("country", {
                  required: true,
                })}
              />
            )}
            onChange={(e, value) => setValue("country", value?.id)}
          />
        )}

        <Button variant="contained" type="submit" sx={{ marginTop: 3 }}>
          Submit
        </Button>
      </form>
    </>
  );
};
解决方案

核心问题是直接给TextField绑定register会让react-hook-form捕获Autocomplete的显示值(国家名称),而非需要的ID。正确做法是用react-hook-form的Controller组件包裹Autocomplete,统一管理表单值同步:

  • 从react-hook-form解构出control和Controller
  • 用Controller包裹Autocomplete,指定表单字段名"country"
  • 通过Controller的render属性,用field对象同步表单状态:
    • 选中选项时,将选项的id传给表单
    • 从表单获取当前ID,匹配对应国家对象作为Autocomplete的选中值
  • 配置getOptionSelected,通过ID判断选中项,确保Autocomplete正确识别选中状态
修改后的完整代码
import { Controller } from "react-hook-form";
// 其他导入保持不变

const Profile = () => {
  const {
    handleSubmit,
    control,
    formState: { errors },
  } = useForm({});

  const [countries, setCountries] = useState([]);

  const submit = async (value) => {
    console.log(value); // 现在输出的country是ID,比如1
  };

  useEffect(() => {
    axios.get("get-countries").then((data) => {
      setCountries(data.data);
    });
  }, []);

  return (
    <>
      <form method="post" onSubmit={handleSubmit(submit)}>
        {countries.length > 0 && (
          <Controller
            name="country"
            control={control}
            rules={{ required: true }}
            render={({ field }) => (
              <Autocomplete
                id="country-select-demo"
                options={countries}
                autoHighlight
                getOptionLabel={(option) => option.country}
                getOptionSelected={(option, value) => option.id === value.id}
                renderOption={(props, option) => (
                  <Box
                    component="li"
                    sx={{ "& > img": { mr: 2, flexShrink: 0 } }}
                    {...props}
                  >
                    <img
                      loading="lazy"
                      width="20"
                      src={`https://flagcdn.com/w20/${option.symbol.toLowerCase()}.png`}
                      srcSet={`https://flagcdn.com/w40/${option.symbol.toLowerCase()}.png 2x`}
                      alt=""
                    />
                    {option.country}
                  </Box>
                )}
                renderInput={(params) => (
                  <TextField
                    {...params}
                    label="Country"
                    inputProps={{
                      ...params.inputProps,
                      autoComplete: "country",
                    }}
                    error={!!errors.country}
                    helperText={errors.country ? "Country is required" : ""}
                  />
                )}
                onChange={(e, selectedOption) => {
                  field.onChange(selectedOption?.id);
                }}
                value={countries.find(country => country.id === field.value) || null}
              />
            )}
          />
        )}

        <Button variant="contained" type="submit" sx={{ marginTop: 3 }}>
          Submit
        </Button>
      </form>
    </>
  );
};
关键说明
  • Controller是react-hook-form专门适配第三方UI组件的工具,能精准同步组件状态与表单状态
  • getOptionSelected必须配置,否则Autocomplete无法通过ID匹配到对应的选项对象
  • 原代码中categories.countries为笔误,改为countries(与useState存储的变量一致)
  • 错误提示通过errors.country控制,保持与react-hook-form的错误状态统一

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 00:40:08