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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 08:47:47