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

MantineUI Autocomplete自定义Item组件无法显示问题求助

Mantine Autocomplete自定义Item组件不显示问题排查

按照Mantine UI官方文档实现Autocomplete的自定义Item组件时,出现以下问题:

  • 使用业务数据productsData时,自定义组件无法显示内容
  • 替换为文档提供的示例数据后,自定义组件可正常展示

以下是相关代码及问题原因分析、解决方案:

我的实现代码

interface SearchProps extends SelectItemProps {
  name: string;
}

const itemSearch = forwardRef<HTMLDivElement, SearchProps>(
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  ({ value, name, ...others }: SearchProps, ref) => (
    <div ref={ref} {...others}>
      <Group>
        <Text>{name}</Text>
        <Text>{value}</Text>
      </Group>
    </div>
  )
);

function Search(props: Omit<ComponentProps<typeof Autocomplete>, "data">) {
  const { products, q } = useLoaderData() as Awaited<ReturnType<typeof loader>>;
  const submit = useSubmit();

  const inputRef = useRef<HTMLFormElement>(null);
  const productsData = products?.map(
    (product: { name: string; _id: string }) => ({
      name: product.name,
      value: product._id,
      label: product.name,
    })
  );
  console.log(productsData);
  return (
    <Form role="search" ref={inputRef} method="GET" className={props.className}>
      <Autocomplete
        itemComponent={itemSearch}
        styles={{
          input: {
            borderRadius: "20px !important",
          },
        }}
        defaultValue={q as string}
        type="search"
        aria-label="Search products"
        placeholder="Search "
        onChange={() => {
          const isFirstSearch = q == null;
          submit(new FormData(inputRef?.current as HTMLFormElement), {
            replace: !isFirstSearch,
          });
        }}
        // icon={<IconSearch size="1rem" stroke={2} />}
        icon={<Loader size="xs" />}
        name="q"
        data={productsData ? productsData : []}
      />
    </Form>
  );
}

export default Search;

文档示例代码

const charactersList = [
  {
    image: 'https://img.icons8.com/clouds/256/000000/futurama-bender.png',
    label: 'Bender Bending Rodríguez',
    description: 'Fascinated with cooking, though has no sense of taste',
  },

  {
    image: 'https://img.icons8.com/clouds/256/000000/futurama-mom.png',
    label: 'Carol Miller',
    description: 'One of the richest people on Earth',
  },
  {
    image: 'https://img.icons8.com/clouds/256/000000/homer-simpson.png',
    label: 'Homer Simpson',
    description: 'Overweight, lazy, and often ignorant',
  },
  {
    image: 'https://img.icons8.com/clouds/256/000000/spongebob-squarepants.png',
    label: 'Spongebob Squarepants',
    description: 'Not just a sponge',
  },
];

const data = charactersList.map((item) => ({ ...item, value: item.label }));

interface ItemProps extends SelectItemProps {
  color: MantineColor;
  description: string;
  image: string;
}

const AutoCompleteItem = forwardRef<HTMLDivElement, ItemProps>(
  ({ description, value, image, ...others }: ItemProps, ref) => (
    <div ref={ref} {...others}>
      <Group noWrap>
        <Avatar src={image} />

        <div>
          <Text>{value}</Text>
          <Text size="xs" color="dimmed">
            {description}
          </Text>
        </div>
      </Group>
    </div>
  )
);

问题原因及解决方案

1. 数据有效性与结构问题

  • 检查products加载状态:通过console.log(products)确认数据不是undefined或空数组,且每个product的name字段为非空有效值。
  • 优化productsData兜底逻辑:避免products为undefined时生成无效数据,强制兜底为空数组:
    const productsData = (products || []).map(
      (product: { name: string; _id: string }) => ({
        name: product.name,
        value: product._id,
        label: product.name,
      })
    );
    

2. defaultValue与value字段不匹配

你设置的defaultValue={q as string}是产品名称,但productsData中每个item的value是产品ID,两者类型不匹配会导致Autocomplete无法正确匹配选项,引发渲染异常:

  • 方案一:统一value与defaultValue类型,将productsData的value改为产品名称:
    const productsData = (products || []).map(product => ({
      name: product.name,
      value: product.name,
      label: product.name,
    }));
    
  • 方案二:匹配对应产品ID作为defaultValue:
    const defaultProduct = products?.find(p => p.name === q);
    <Autocomplete
      defaultValue={defaultProduct?._id || ''}
      // ...其他props
    />
    

3. onChange事件触发页面跳转打断渲染

当前onChange事件在用户输入时立即提交表单,会触发页面导航,导致下拉列表未完成渲染就被刷新打断:

  • 改为监听onSelect事件(用户选中下拉选项时触发)再提交表单:
    <Autocomplete
      // ...其他props
      onSelect={() => {
        const isFirstSearch = q == null;
        submit(new FormData(inputRef?.current as HTMLFormElement), {
          replace: !isFirstSearch,
        });
      }}
      // 移除原有的onChange
    />
    

4. 类型定义优化

显式定义productsData的类型,确保字段完整性,避免类型隐式转换问题:

type ProductAutocompleteItem = {
  name: string;
  value: string;
  label: string;
};

const productsData: ProductAutocompleteItem[] = (products || []).map(
  (product: { name: string; _id: string }) => ({
    name: product.name,
    value: product._id,
    label: product.name,
  })
);

内容的提问来源于stack exchange,提问作者VN-Boy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 08:44:56