问题如下:
我有几千个元素列表的数据。其中一些是重复的,然后可能有重复键的机会。因为我没有真正的“ID”或任何能让我有机会将所有元素作为唯一键的ID的东西,是否可以使用Math.random()
代替?
据我所知,密钥主要用于区分组件。我认为,就我的代码中的密钥没有任何关系,这应该没问题?为了确保没有重复的数字,我可以将两个数学格式相互分开以获得几乎肯定唯一的密钥。
这是一个好习惯吗?我可以使用它而不必担心任何事情吗?
每次组件的键改变时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如何为新人找到这个答案选择一把钥匙
只需在您的react组件中实现以下代码......
constructor( props ) {
super( props );
this.keyCount = 0;
this.getKey = this.getKey.bind(this);
}
getKey(){
return this.keyCount++;
}
...并在每次需要新密钥时调用this.getKey()
:
key={this.getKey()}
如果您不提供稳定键(例如,通过使用Math.random()),则每次都会重新渲染所有子树。通过让用户选择按键,他们有能力在脚下射击。
密钥应该是稳定的,可预测的和唯一的。不稳定的密钥(如Math.random()生成的密钥)将导致许多组件实例和DOM节点被不必要地重新创建,这可能导致性能下降和子组件中的丢失状态。
这是一个好习惯吗?我可以使用它而不必担心任何事情吗?
不,不。
密钥应该是稳定的,可预测的和唯一的。不稳定的密钥(如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的信息
我认为为组件键提供Math.random()是不正确的,原因是当你生成随机数时,不能保证不再获得相同的数字。很可能在渲染组件时再次生成相同的随机数,因此该时间将失败。
有些人会争辩说,如果随机数范围越大,则不太可能再次生成数字。是的,但您的代码可以随时生成警告。
其中一种快速方法是使用新的Date(),它将是唯一的。