问题如下:
我有几千个元素列表的数据.其中一些是重复的,然后可能有重复键的机会.因为我没有真正的"ID"或任何能让我有机会将所有元素作为唯一键的ID,所以可以使用Math.random()
吗?
据我所知,密钥主要用于区分组件.我认为,就我的代码中的密钥没有任何关系,这应该没问题?为了确保没有重复的数字,我可以将两个数学格式相互分开以获得几乎肯定唯一的密钥.
这是一个好习惯吗?我可以使用它而不必担心任何事情吗?
Mar*_*pse 42
每次组件的密钥更改时,React都会创建一个新的组件实例,而不是更新当前的组件实例,因此为了性能,使用Math.random()至少可以说是次优的.
此外,如果您要以任何方式重新排序组件列表,使用索引作为键将无济于事,因为React协调器将无法仅移动与组件关联的现有DOM节点,而是必须重新启动 - 为每个列表项创建DOM节点,这将再次具有次优性能.
但重申一下,如果您要重新排序列表,这只会是一个问题,所以在您的情况下,如果您确定不会以任何方式重新排序列表,您可以安全地使用索引作为键.
但是,如果您打算重新排序列表(或者只是为了安全),那么我将为您的实体生成唯一的ID - 如果没有预先存在的唯一标识符,则可以使用.
添加ID的一种快速方法是在第一次接收(或创建)列表时映射列表并为每个项目分配索引.
const myItemsWithIds = myItems.map((item, index) => { ...item, myId: index });
Run Code Online (Sandbox Code Playgroud)
这样每个项目都会获得一个唯一的静态ID.
tl; dr如何为新人找到这个答案选择一把钥匙
如果您的列表项具有唯一ID(或其他唯一属性),请将其用作密钥
如果您可以组合列表项中的属性以创建唯一值,请将该组合用作键
如果上述工作都没有,但你可以小姐承诺你不会以任何方式重新排序列表,你可以使用数组索引作为键,但你最好在列表中添加自己的id到列表项首先收到或创建(见上文)
小智 14
只需在您的react组件中实现以下代码......
constructor( props ) {
super( props );
this.keyCount = 0;
this.getKey = this.getKey.bind(this);
}
getKey(){
return this.keyCount++;
}
Run Code Online (Sandbox Code Playgroud)
...并在this.getKey()
每次需要新密钥时调用,例如:
key={this.getKey()}
Run Code Online (Sandbox Code Playgroud)
Sh*_*rim 8
这是一个好的做法吗?我可以使用这个而不必担心任何事情吗?
不,不。
密钥应该稳定、可预测且唯一。不稳定的键(例如由 Math.random() 生成的键)将导致许多组件实例和 DOM 节点不必要地重新创建,这可能会导致子组件的性能下降和状态丢失。
让我用一个简单的例子来说明这一点。
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}/>)
};
};
Run Code Online (Sandbox Code Playgroud)
为什么我不能在您要求的输入中输入多个字符?
这是因为我使用 Math.random() 作为关键属性来映射多个文本输入。每次我输入一个字符时, onChange 属性都会触发,并且父组件的状态会发生变化,从而导致重新渲染。这意味着每次输入都会再次调用 Math.random 并生成新的 key props。因此,react 会渲染新的子 Input 组件。换句话说,每次键入字符时,react 都会创建一个新的输入元素,因为 key prop 发生了变化。
在这里阅读更多相关内容
其他答案说这Math.random()
是一个坏主意,但这只说对了一半。Math.random()
如果我们在最初接收数据时而不是在渲染时这样做,那么使用它是完全可以接受的。
例如:
function SomeComponent() {
const [items, setItems] = React.useState(() => []);
React.useEffect(() => {
fetch('/api/data')
.then((res) => res.json())
.then((data) => {
const itemsWithIds = data.map((item) => {
return {
...item,
id: Math.random(),
};
});
setItems(itemsWithIds);
});
}, []);
return (
<div>
{items.map((item) => (
<Item key={item.id} item={item} />
))}
</div>
);
}
Run Code Online (Sandbox Code Playgroud)
当我收到数据时,我会映射列表中的每个项目并附加一个带有Math.random()
. 渲染时,我使用之前创建的 ID 作为键。
最重要的是我们不会在每次渲染时重新生成密钥。通过这种设置,当我们从 API 接收数据时,我们只生成一次密钥。
您可以在几乎所有情况下使用此模式,甚至对于本地数据也是如此。在调用状态设置器之前(或者在初始化状态挂钩之前),您可以为每个项目生成唯一的 ID。
您还可以使用crypto.randomUUID()
Math.random() 来生成 uuid 而不是随机数。
归档时间: |
|
查看次数: |
26171 次 |
最近记录: |