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

问题描述 投票:29回答:6

问题如下:

我有几千个元素列表的数据。其中一些是重复的,然后可能有重复键的机会。因为我没有真正的“ID”或任何能让我有机会将所有元素作为唯一键的ID的东西,是否可以使用Math.random()代替?

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

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

reactjs
6个回答
31
投票

每次组件的键改变时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列表项首先收到或创建(见上文)

6
投票

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

constructor( props ) {
    super( props );

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

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

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

key={this.getKey()}

5
投票

来自react documentation

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


2
投票

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

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


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 prop都会触发,而父组件的状态会发生变化,从而导致重新渲染。这意味着每次输入都会再次调用Math.random,并生成新的键道具。因此,生成新的子项输入组件。换句话说,每次键入一个字符时,react会创建一个新的输入元素,因为键道具已更改。

了解更多关于这个here的信息


0
投票

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

有些人会争辩说,如果随机数范围越大,则不太可能再次生成数字。是的,但您的代码可以随时生成警告。

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

© www.soinside.com 2019 - 2024. All rights reserved.