[英]Different ways to add a key to JSX element in loop in React
I have been working on react for more than an year now. 我已经做了一年多的反应。 I have mostly played with iterating an array using .map, .forEach, .filter or using Object.keys and Object.values if it is an object.
我主要使用.map,.forEach,.filter或使用Object.keys和Object.values迭代一个数组(如果它是一个对象)。
But what are the different ways to add a unique key to jsx element. 但是为jsx元素添加唯一键的不同方法有哪些。 Below is what I have been used to till now
以下是我到目前为止所习惯的
Using unique id from data as key to key prop: 使用数据中的唯一ID作为关键道具的关键:
const data= [{"id": "01", "name": "abc"}, {"id": "02", "name": "xyz"}];
render(){
const items = data.map(item => {
return <span key={item.id}>{item.name}</span>;
}
return(
<div>
{items}
</div>
)
}
Using index as key to key prop: 使用索引作为关键道具的关键:
const data= [{"id": "01", "name": "abc"}, {"id": "02", "name": "xyz"}];
render(){
const items = data.map((item, i) => {
let keyValue = i+1;
return <span key={keyValue}>{item.name}</span>;
}
return(
<div>
{items}
</div>
)
}
Is there any other ways to add a unique key to the jsx element apart from what I have mentioned above and which is most efficient and recommended? 除了我上面提到的以及最有效和推荐的方法之外,还有其他方法可以为jsx元素添加唯一键吗?
First of all, avoid using random keys . 首先, 避免使用随机密钥 。
There are a lot of ways to write keys, and some will perform better than others. 写密钥有很多种方法,有些方法比其他方式更好。
To understand how the keys we've chosen impacts on performance, it's necessary to understand React's Reconciliation Algorithm. 要了解我们选择的密钥如何影响性能,有必要了解React的协调算法。
https://reactjs.org/docs/reconciliation.html https://reactjs.org/docs/reconciliation.html
tl;dr Introduces a heuristic for comparing Virtual DOM trees to make this comparison O(n), with n the nodes of this VDOM tree. tl; dr引入一种启发式,用于比较虚拟DOM树以进行此比较O(n),其中n为此VDOM树的节点。 This heuristic can be split in these points:
这种启发式可以分为以下两点:
<Button />
to <NotButton />
), will cause to our Button to be unmounted with its children as well, and NotButton to be mounted with its children, as well. <Button />
到<NotButton />
),将导致将我们的Button与其子项一起卸载,并将NotButton与其子项一起安装。 Supose now that we have this: 现在说我们有这个:
<div>
<Button title="One" />
<Button title="Two" />
</div>
And we'd like to add a Button to the DOM on the next render, say 我们想在下一个渲染中为DOM添加一个Button,比如说
<div>
<Button title="Zero" />
<Button title="One" />
<Button title="Two" />
</div>
The algorithm will go as follows: 算法将如下:
<divs>
in both VDOMs. <divs>
。 Since these have the same type, we don't need to recreate the new tree. One
compares against Zero
. One
与Zero
比较。 Reconciler detects that here was a props change, then updates the DOM with this title. Two
compares against One
. Two
与One
。 Reconcilier also detects a props change here and uses the DOM to write this change. Button
is added as last child, so creates a new Button
instance at VDOM and write this change at DOM. Button
被添加为最后一个子节点,因此在VDOM处创建一个新的Button
实例并在DOM处写入此更改。 Notice that these has many operations on the DOM, because it compared components by their index. 请注意,它们在DOM上有许多操作,因为它通过索引比较组件。
Now, we can fix this behavior by letting know to our reconciler that these instances should be reused. 现在,我们可以通过告知我们的协调程序应该重用这些实例来解决此问题。 Now, let's have this:
现在,让我们有这个:
<div>
<Button title="One" key="One" />
<Button title="Two" key="Two" />
</div>
And we'd like to add a Button to the DOM on the next render, say 我们想在下一个渲染中为DOM添加一个Button,比如说
<div>
<Button title="Zero" key="Zero" />
<Button title="One" key="One" />
<Button title="Two" key"Two" />
</div>
The algorithm will go as follows: 算法将如下:
<divs>
in both VDOMs. <divs>
。 Since these have the same type, we don't need to recreate the new tree. Button
', says the reconciler. Button
。 'And has a key' ('One'). Button
, it will compare by keys
instead of by index
. Button
会出现相同的情况,它将通过keys
而不是index
进行比较。 Realizes that it's the same instance and no props were changed, so React decides to not apply changes on the DOM. Button
with 'Zero' key, since there no exists a child with the same key , realizes that an instance should be created at VDOM, and this change should be written on DOM. Button
,由于没有具有相同键的子项 ,因此意识到应该在VDOM上创建实例,并且此更改应该写在DOM上。 So, using keys by predictable contents helps the reconciler to perform less operations on the DOM. 因此,通过可预测内容使用密钥有助于协调程序对DOM执行较少的操作。 Healthy keys are those that can be inferred from the object that is being mapped, like a
name
, or an id
or even an url
if we are transforming urls
to <imgs />
. 健康键是那些可以从被映射的对象推断出来的键,如
name
, id
或甚至是url
如果我们将urls
转换为<imgs />
。
What about key=index
? 那么
key=index
呢? Will have no effect, since by default, reconciler compares by position, ie its index. 将无效,因为默认情况下,协调程序按位置进行比较,即其索引。
These keys should be globally unique? 这些键应该是全球唯一的吗? Not necessarily.
不必要。 These should be unique among siblings, so reconciler can distinguish them while iterating by a node's children.
这些在兄弟姐妹中应该是唯一的,因此协调者可以在节点的子节点迭代时区分它们。
What about random keys? 随机键怎么样? These should be avoided at all costs.
应不惜一切代价避免这些。 If a key changes on every render, this will be keeping React destroying and creating instances on the VDOM (and hence, making extra writes on the DOM) since a component with a key wasn't found among the new children, but a new one with the same type.
如果一个键在每个渲染上发生变化,这将使React破坏并在VDOM上创建实例(因此,在DOM上进行额外的写入),因为在新的子节点中找不到具有键的组件,而是新的子节点具有相同的类型。
If the render output is like 如果渲染输出是这样的
<div>
<Button key={randomGenerator()} />
</div>
Then, each time render
is executed (eg due a props/state change, or even if it's parent is being re-rendered and our shouldComponentUpdate
returns true
), a new randomGenerator()
key will be generated. 然后,每次执行
render
(例如,由于道具/状态更改,或者即使它的父级正在重新渲染并且我们的shouldComponentUpdate
返回true
),也会生成一个新的randomGenerator()
键。 This will go like: 这将是:
'Hey! '嘿! I've found a
Button
with a F67BMkd==
key, but none was found in the next one. 我找到了一个带有
F67BMkd==
键的Button
,但没有找到下一个。 I'll delete it.' 我会删除它。 'Oh!
'哦! I've encountered a
Button
with a SHDSA++5
key! 我遇到了一个带有
SHDSA++5
键的Button
! Let's create a new one'. 让我们创建一个新的'。
Whenever the reconciler tells that an instance should be deleted and unmounted, its internal state will be lost; 每当协调程序告知应删除和卸载实例时,其内部状态将丢失; even if we mount it again.
即使我们再次安装它。 The instance at VDOM will not be preserved in this case.
在这种情况下,VDOM的实例不会被保留。
The Button
was the same, but the reconciler did a mess at DOM. Button
是相同的,但协调员在DOM上弄得一团糟。
Hope it helps. 希望能帮助到你。
The best way to pick a key is to use a string that uniquely identifies a list item among its siblings. 选择密钥的最佳方法是使用在其兄弟姐妹中唯一标识列表项的字符串。 Most often you would use IDs from your data as keys:
大多数情况下,您会使用数据中的ID作为键:
const todoItems = todos.map((todo) =>
<li key={todo.id}>
{todo.text}
</li>
);
When you don't have stable IDs for rendered items, you may use the item index as a key as a last resort: 当您没有渲染项目的稳定ID时,您可以使用项目索引作为关键作为最后的手段:
const todoItems = todos.map((todo, index) =>
// Only do this if items have no stable IDs
<li key={index}>
{todo.text}
</li>
);
Also note: 另请注意:
Keys used within arrays should be unique among their siblings.
数组中使用的键在其兄弟姐妹中应该是唯一的。 However they don't need to be globally unique.
但是,它们不需要是全球唯一的。
However real answer to your question lives here: https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318 但是你的问题的真实答案就在这里: https : //medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318
There are many libraries that generate random unique ids such as shortid or uuid (which is the most popular one, just look at the number of downloads) or else just create your own function that generates random strings. 有许多库可以生成随机唯一ID,例如shortid或uuid (这是最受欢迎的ID,只需查看下载次数),或者只是创建自己的函数来生成随机字符串。
You can add them directly into object in array 您可以将它们直接添加到数组中的对象中
const todos = [
{
id: uuid(),
text: 'foo',
}
]
and iterate like so: 并迭代如下:
const todoItems = todos.map(({id, text}) =>
<li key={id}>
{text}
</li>
);
md5 sha1甚至sha256的内容。
You can use Date.now() with index , your code will be as Ex. 您可以将Date.now()与索引一起使用 ,您的代码将为Ex。
const data= [{"id": "01", "name": "abc"}, {"id": "02", "name": "xyz"}];
render(){
const items = data.map((item, i) => {
let keyValue = Date.now()+i;
return <span key={keyValue}>{item.name}</span>;
}
return(
<div>
{items}
</div>
)
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.