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

MUI V5类组件自定义Autocomplete支持新增输入及显示问题修复

问题根因

MUI v5对Autocomplete组件的API做了两处不兼容调整,直接导致你遇到的两个问题:

  1. renderOption 属性的入参顺序变化:v4直接传入option对象,v5第一个参数是li元素的属性对象,第二个参数才是option对象,你现有代码拿不到正确的option值,所以新增选项提示无法显示
  2. 未配置isOptionEqualToValue默认逻辑:v5默认用对象严格相等判断选中值和选项的匹配关系,如果选中值和options数组里的对应项不是同一个引用,就会匹配失败,导致初始加载显示为空

修复代码

1. 自定义SingleSoloSelect2组件修改

import React from 'react';
import TextField from '@mui/material/TextField';
import Autocomplete from '@mui/material/Autocomplete';

const SingleSoloSelect2 = (props) => {
  const filter = (options, params) => {
      let inList = false;
      const filtered = options.filter(o => {
          if (!params.inputValue) return true;

          const value = o[props.labelField].toLowerCase();
          const input = params.inputValue.toLowerCase();
          if (value === input) inList = true;
          if (value.includes(input)) return true;

          return false;
      });

      return { inList, filtered };
  }

    return (
        <Autocomplete
            fullWidth
            freeSolo={props.freeSolo ?? true}
            id={props.id}
            value={props.value}
            options={props.options || []}
            disabled={props.disabled}
            selectOnFocus
            clearOnBlur
            handleHomeEndKeys
            onChange={(e, v) => {
                let isNew = false;
                if (typeof v === 'string') {
                  // 兼容v5 freeSolo模式返回字符串的情况,转成统一对象格式
                  v = {
                    [props.valueField]: v,
                    [props.labelField]: v,
                    new: true
                  }
                  isNew = true;
                } else if (v?.new) {
                  isNew = true;
                }
                props.onChange(v, isNew, props.id);
            }}
            getOptionLabel={props.getOptionLabel ?? ((option) => option?.[props.labelField] ?? '')}
            filterOptions={(options, params) => {
                const { inList, filtered } = filter(options, params);
                if ((props.freeSolo ?? true) && params.inputValue !== '' && !inList) {
                    filtered.push({
                        [props.valueField]: params.inputValue,
                        [props.labelField]: params.inputValue,
                        new: true,
                    });
                }
                return filtered;
            }}
            // 修复入参顺序,第一个是li的属性参数,避免和组件props重名
            renderOption={(liProps, option) => {
              return (
                <li {...liProps}>
                  {option.new
                    ? `新增 "${option[props.labelField]}"`
                    : option[props.labelField]}
                </li>
              )
            }}
            // 增加默认匹配逻辑,解决初始值匹配失败为空的问题
            isOptionEqualToValue={props.isOptionEqualToValue ?? ((option, value) => {
              return option?.[props.valueField] === value?.[props.valueField]
            })}
            renderInput={(params) => (<TextField {...params} label={props.label} variant={props.variant} size={props.size} error={props.error} />)}
          />
        );
      }

export default SingleSoloSelect2;

2. handleSingleSelect逻辑优化(可选)

handleSingleSelect = (v, isNew) => {
  // 避免直接修改state,符合React immutable规范
  const q = {...this.state.activeQuestion};
  q.value = v;
  if (isNew) {
    // 去掉new标记再存到options,避免后续选项里显示新增标识
    const newOption = {...v};
    delete newOption.new;
    q.options.push(newOption);
  }
  this.setState({ activeQuestion: q });
}

额外调整说明

  • 修复了freeSolo默认值的判断,用空值合并运算符??替代原来的三元判断,更简洁
  • 修正了onChange里新值的处理逻辑,统一转成对象格式,避免后续业务逻辑同时处理字符串和对象两种格式
  • 增加了getOptionLabel的默认值,不传的话也可以根据labelField自动读取,减少调用时的重复代码

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 00:45:05