MaterialUI Autocomplete问题:重复Key错误与自定义卡片布局实现
解决方案:MaterialUI Autocomplete 两个问题处理
1. 解决重复Key报错问题
- 不要将
options处理为仅含名称的数组,直接传递完整的Items对象数组,避免同名导致的Key冲突 - 若后端返回数据无
itemId,在获取数据时为每个条目生成uuid作为唯一标识 - 通过
getOptionLabel指定输入框显示的文本,用getOptionKey配置使用itemId作为React Key
2. 实现自定义卡片式建议项
- 使用Autocomplete的
renderOption属性自定义每个建议项的布局,无需手动调用.map() - 借助MUI的
Box、Avatar等组件实现左侧头像、右侧信息的卡片布局
修正后的完整代码
import { Autocomplete, TextField, Typography, Box, Avatar } from "@mui/material"; import { Fragment, useEffect, useState } from "react"; import uuid from "react-uuid"; import agent from "../../../api/agent"; import { Items } from "../../../models/Job"; import { setCloseMenu, setOpenMenu } from "../../menu/menuSlice"; import { useAppDispatch, useAppSelector } from "../../Redux/reduxStore"; interface Props { searchTerm?: string; } export default function JobSearch(props: Props) { const [items, setItems] = useState<Items[]>([]); const dispatch = useAppDispatch(); const { status } = useAppSelector(state => state.menu); useEffect(() => { agent.Product.getAutoCompleteProducts() .then(rawItems => { // 为每个商品添加唯一itemId const itemsWithId = rawItems.map(item => ({ ...item, itemId: uuid() })); setItems(itemsWithId); }) .catch(error => console.log(error)); }, []); return ( <Fragment> <Autocomplete open={status.name === "autoCompleteMenu" && status.open} onOpen={() => dispatch(setOpenMenu("autoCompleteMenu"))} onClose={() => dispatch(setCloseMenu("autoCompleteMenu"))} options={items} getOptionLabel={(option) => option.itemName} getOptionKey={(option) => option.itemId} renderOption={(props, option) => ( <Box component="li" {...props} sx={{ display: 'flex', alignItems: 'center', gap: 2, padding: 2, cursor: 'pointer', borderBottom: '1px solid #eee' }}> {/* 左侧头像,可替换为实际图片地址 */} <Avatar sx={{ width: 48, height: 48, bgcolor: 'primary.main' }}> {option.itemName.charAt(0)} </Avatar> {/* 右侧商品信息 */} <Box sx={{ flex: 1 }}> <Typography variant="h6" sx={{ fontWeight: 500 }}>{option.itemName}</Typography> <Typography variant="body2" color="text.secondary">${option.itemPrice.toFixed(2)}</Typography> <Typography variant="body2" color="text.secondary" sx={{ marginTop: 0.5 }}> {option.itemDesc} </Typography> </Box> </Box> )} renderInput={(params) => ( <TextField {...params} variant='outlined' placeholder="搜索商品" /> )} /> </Fragment> ); }
关键说明
getOptionKey:显式指定用itemId作为每个选项的唯一Key,彻底解决"重复Key"报错renderOption:必须将props解构传入根元素(这里是Box),以保留Autocomplete的选中、高亮等交互逻辑;内部通过弹性布局实现卡片样式- 数据处理:在获取后端数据时补充
itemId,确保每个条目有唯一标识(若后端已返回itemId可跳过此步骤)
内容的提问来源于stack exchange,提问作者Himanshu Sharma
相关产品推荐
相关产品推荐

