首页 > 解决方案 > 为什么提供 key={index} 会导致与不定义键不同的行为?

问题描述

如果我们定义它,事情就会起作用,如果我们排除它,事情就不会起作用,但我希望根据文档,行为是相同的。key={index}

根据文档

如果您选择不为列表项分配显式键,那么 React 将默认使用索引作为键。

为什么会这样?不提供任何密钥不应该等同于提供key={index}吗?

标签: javascriptreactjsecmascript-6

解决方案


文档措辞不当:如果您没有指定一个键,React 实际上不会使用键并且离开键属性与使用key={index}. 相反,如果不存在 key 属性,React 将基于其虚拟 DOM 父元素中元素的子索引进行内部检查。这些可能(并且通常会)与您的迭代索引相同,但肯定并非总是如此,并且依赖它们相同会导致错误。

对于“迭代索引”和“虚拟 DOM 子索引”不同时的示例,让我们看一下我们从多个输入列表创建子元素的情况。如果我们不指定key属性,React 会警告缺少键,但一切都会按预期工作:

class App extends Component {
  constructor(props) {
    super(props);  
    this.state = {
      a: [1,2,3],
      b: [4,5,6]
   };
  }
  render() {
    const { a, b } = this.state;
    return <div>{
      a.map(e => <p>{e}</p>).concat(b.map(e => <p>{e}</p>))
    }div>;
  }
}

我们得到六个无键段落,内容从 1 到 6,正如您想象的那样,我们只看代码就会得到。

但是,如果我们遵循 React 的建议并添加key属性,但我们错误地将数组索引用作键,这是你不应该做的事情,事情就会停止按预期工作:

class App extends Component {
  constructor(props) {
    super(props);  
    this.state = {
      a: [1,2,3],
      b: [4,5,6]
   };
  }
  render() {
    const { a, b } = this.state;
    return <div>{
      a.map((e,index) => <p key={index}>{e}</p>)
       .concat(b.map((e, index) => <p key={index}>{e}</p>))
    }div>;
  }
}

现在将显示内容为 1 到 3 的三个段落,因为这两个数组映射会产生带有键的元素,但也会产生键冲突。由于 from 的所有元素b都有与 from 的元素发生冲突的键a,React 会将它们丢弃,现在你有一个 bug 需要寻找。

当然,如果您正在编写正确的 React,那么您通常不会遇到这种情况。始终使用键,并始终确保它们唯一标识您正在映射的元素。

也就是说,我已经提交了https://github.com/reactjs/reactjs.org/issues/3732以希望更新该文本以明确说明该文本不是在谈论您的代码正在运行的任何迭代的索引但它自己的内部子节点索引。


推荐阅读