Next.js中使用Material UI Autocomplete遇key属性展开警告求解决
解决Next.js中Material UI Autocomplete的Key属性Hydration警告
问题场景
在Next.js项目中使用Material UI的Autocomplete多选组件时,触发了hydration警告,排查发现renderInput的params中并没有key属性,无法按照警告提示直接移除:
const top100Films = ['a', 'b', 'c', 'd']; // props.tags = ['a', 'c'] <Autocomplete multiple id="tags-outlined" onChange={(event: any, newValue: string[]) => { props.onTagsChange(newValue); }} options={top100Films} value={props.tags} filterSelectedOptions renderInput={(params) => ( <TextField {...params} label="Tags" placeholder="Tag" /> )} />
警告信息:
hydration-error-info.js?32aa:26 Warning: A props object containing a "key" prop is being spread into JSX: let props = {key: someKey, tabIndex: ..., role: ..., id: ..., onMouseOver: ..., onClick: ..., onTouchStart: ..., data-option-index: ..., aria-disabled: ..., aria-selected: ..., className: ..., children: ...}; <li {...props} /> React keys must be passed directly to JSX without using spread: let props = {tabIndex: ..., role: ..., id: ..., onMouseOver: ..., onClick: ..., onTouchStart: ..., data-option-index: ..., aria-disabled: ..., aria-selected: ..., className: ..., children: ...}; <li key={someKey} {...props} />
问题原因
这个警告并非来自renderInput中的TextField,而是Autocomplete内部渲染选项列表时的问题。当使用简单字符串数组作为options时,Material UI内部生成key的逻辑在服务端渲染(SSR)和客户端hydration阶段可能出现不一致,导致key属性被错误地通过props spread传递给<li>元素,触发React的hydration校验警告。
修复方案
方案1:改用带唯一标识的对象数组(推荐)
将字符串数组改为包含唯一ID的对象数组,同时通过getOptionLabel指定显示文本,确保组件能稳定生成一致的key:
const top100Films = [ { id: 1, name: 'a' }, { id: 2, name: 'b' }, { id: 3, name: 'c' }, { id: 4, name: 'd' }, ]; <Autocomplete multiple id="tags-outlined" onChange={(event, newValue) => { // 将选中的对象数组转换回字符串数组传递给父组件 props.onTagsChange(newValue.map(item => item.name)); }} options={top100Films} // 指定选项显示的文本字段 getOptionLabel={(option) => option.name} // 将props.tags转换为对应的对象数组匹配组件值 value={top100Films.filter(film => props.tags.includes(film.name))} filterSelectedOptions renderInput={(params) => ( <TextField {...params} label="Tags" placeholder="Tag" /> )} />
方案2:添加明确的选项匹配逻辑(快速临时修复)
如果不想修改options结构,可以通过isOptionEqualToValue明确指定选项与选中值的匹配逻辑,同时添加disablePortal避免部分hydration不匹配问题:
const top100Films = ['a', 'b', 'c', 'd']; // props.tags = ['a', 'c'] <Autocomplete multiple id="tags-outlined" onChange={(event: any, newValue: string[]) => { props.onTagsChange(newValue); }} options={top100Films} value={props.tags} // 明确选项与值的匹配规则 isOptionEqualToValue={(option, value) => option === value} disablePortal filterSelectedOptions renderInput={(params) => ( <TextField {...params} label="Tags" placeholder="Tag" /> )} />
内容的提问来源于stack exchange,提问作者cjmling
相关产品推荐
相关产品推荐

