给组件提供唯一键时,可以使用Math.random()生成这些键吗?

时间:2015-04-22 20:55:51

标签: reactjs

问题如下:

我有几千个元素列表形式的数据。其中一些是重复的,然后可能有重复键的机会。 因为我没有真正的“ID”或任何可以让我有机会将所有元素作为唯一键的ID,所以可以使用std::forward吗?

据我所知,密钥主要用于区分组件。我认为,就我的代码中的密钥没有任何关系,这应该没问题?为了确保没有重复的数字,我可以将两个数学格式相互划分,以获得几乎肯定唯一的密钥。

这是一个好习惯吗?我可以使用它而不必担心任何事情吗?

7 个答案:

答案 0 :(得分:30)

每次组件的键更改时React将create a new component instance rather than update the current one,因此为了性能,使用Math.random()至少可以说是次优的。

此外,如果您要以任何方式重新排序组件列表,使用索引作为键将不会有用,因为React协调程序将无法仅移动与现有关联的DOM节点使用组件,它将不得不为每个列表项重新创建DOM节点,这将再次具有次优性能。

但重申一下,如果您要重新订购列表,这只会是一个问题,所以在您的情况下,如果您确定不会以任何方式重新排序列表,你可以安全地使用索引作为密钥。

但是,如果您打算重新排序列表(或者只是为了安全),那么我会为您的实体生成唯一的ID - 如果没有预先存在的唯一标识符,您可以使用。

添加ID的一种快捷方法是在第一次接收(或创建)列表时映射列表并为每个项分配索引。

const myItemsWithIds = myItems.map((item, index) => { ...item, myId: index });

这样每个项目都会获得一个唯一的静态ID。

tl; dr如何为新人找到这个答案选择一个密钥

  1. 如果您的列表项具有唯一ID(或其他唯一属性) 将其用作关键

  2. 如果您可以合并列表项中的属性以创建唯一值,请将该组合用作键

  3. 如果上述任何一项工作都没有,但你可以小姐承诺你不会以任何方式重新排序你的列表,你可以使用数组索引作为键,但你可能更好地添加自己的ID首次接收或创建列表时的列表项(见上文)

答案 1 :(得分:6)

只需在您的反应组件中实现以下代码......

constructor( props ) {
    super( props );

    this.keyCount = 0;
    this.getKey = this.getKey.bind(this);
}

getKey(){
    return this.keyCount++;
}

...并在每次需要新密钥时调用this.getKey(),如:

key={this.getKey()}

答案 2 :(得分:5)

来自react documentation

  

如果您不提供稳定键(例如,使用Math.random()),则每次都会重新渲染所有子树。通过让用户选择按键,他们可以自己射击。

答案 3 :(得分:2)

密钥应该稳定,可预测且独特。不稳定的密钥(如Math.random()生成的密钥)将导致许多组件实例和DOM节点被不必要地重新创建,这可能导致性能下降和子组件中的状态丢失。

https://facebook.github.io/react/docs/reconciliation.html

答案 4 :(得分:1)

  

这是一个好习惯吗?我可以不用担心而使用它吗?

不,不。

  

密钥应稳定,可预测且唯一。不稳定的键(如Math.random()产生的键)将导致不必要地重新创建许多组件实例和DOM节点,这可能导致性能下降和子组件中的状态丢失。

让我用simple example进行说明。

class Input extends React.Component {
  handleChange = (e) =>  this.props.onChange({
    value: e.target.value,
    index: this.props.index
  });
  render() {
    return (
      <input value={this.props.value} onChange={this.handleChange}/>  
    )
  }
};

class TextInputs extends React.Component {
  state = {
    textArray: ['hi,','My','Name','is']
  };
  handleChange = ({value, index}) => {
    const {textArray} = this.state;
    textArray[index] = value;
    this.setState({textArray})
  };
  render(){
  return this.state.textArray.map((txt, i) => <Input onChange={this.handleChange} index={i} value={txt} key={Math.random()}/>)
  // using array's index is not as worse but this will also cause bugs.  
  // return this.state.textArray.map((txt, i) => <Input onChange={this.handleChange} index={i} value={txt} key={i}/>)                 
  };
};

为什么我在输入的内容中不能输入多个字符?

这是因为我正在使用Math.random()作为关键道具来映射多个文本输入。每次我键入一个字符时,onChange道具都会触发,并且父组件的状态会发生变化,从而导致重新渲染。这意味着每个输入都会再次调用Math.random并生成新的键道具,因此react会渲染新的子级Input组件。换句话说,每次键入字符时react都会创建一个新的输入元素,因为键道具已更改。

详细了解此here

答案 5 :(得分:0)

我认为为组件键提供Math.random()是不正确的,原因是当您生成随机数时,不能保证不会再获得相同的数字。渲染组件时很可能会再次生成相同的随机数,因此这一次将失败。

有人会争辩说,如果随机数范围更大,那么将不会再次生成数字的可能性很小。是的,但是您的代码可以随时生成警告。

一种快速的方法是使用新的Date(),它将是唯一的。

答案 6 :(得分:-1)

密钥应稳定,可预测且唯一。 不稳定的键(例如Math.random()产生的键)将导致不必要地重新创建许多组件实例和DOM节点,这可能导致性能下降和子组件中的状态丢失。

您应该为每个子项以及子项中的每个元素添加一个 key

这样,React可以处理最小的DOM变化。

请通过https://reactjs.org/docs/reconciliation.html#recursing-on-children。在这里,您将获得带有代码示例的最佳解释。