Как создать уникальные ключи для элементов React?
Я делаю приложение React, которое позволяет вам создавать список и сохранять его, но React предупреждает меня, что у моих элементов нет уникальной подсказки ключа (элементы List/ListForm). Как создать уникальную подсказку для созданных пользователем элементов? Ниже мой код React
var TitleForm = React.createClass({
handleSubmit: function(e) {
e.preventDefault();
var listName = {'name':this.refs.listName.value};
this.props.handleCreate(listName);
this.refs.listName.value = "";
},
render: function() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<input className='form-control list-input' type='text' ref='listName' placeholder="List Name"/>
<br/>
<button className="btn btn-primary" type="submit">Create</button>
</form>
</div>
);
}
});
var ListForm = React.createClass({
getInitialState: function() {
return {items:[{'name':'item1'}],itemCount:1};
},
handleSubmit: function(e) {
e.preventDefault();
var list = {'name': this.props.name, 'data':[]};
var items = this.state.items;
for (var i = 1; i < items.length; i++) {
list.data.push(this.refs[items[i].name]);
}
this.props.update(list);
$('#'+this.props.name).remove();
},
handleClick: function() {
this.setState({
items: this.state.items.concat({'name':'item'+this.state.itemCount+1}),
itemCount: this.state.itemCount+1
});
},
handleDelete: function() {
this.setState({
itemCount: this.state.itemCount-1
});
},
render: function() {
var listItems = this.state.items.map(function(item) {
return (
<div>
<input type="text" className="list-form" placeholder="List Item" ref={item.name}/>
<br/>
</div>
);
});
return (
<div>
<form onSubmit={this.handleSubmit} className="well list-form-container">
{listItems}
<br/>
<div onClick={this.handleClick} className="btn btn-primary list-button">Add</div>
<div onClick={this.handleDelete} className="btn btn-primary list-button">Delete</div>
<button type="submit" className="btn btn-primary list-button">Save</button>
</form>
</div>
)
}
});
var List = React.createClass({
getInitialState: function() {
return {lists:[], savedLists: []};
},
handleCreate: function(listName) {
this.setState({
lists: this.state.lists.concat(listName)
});
},
updateSaved: function(list) {
this.setState({
savedLists: this.state.savedLists.concat(list)
});
},
render: function() {
var lst = this;
var lists = this.state.lists.map(function(list) {
return(
<div>
<div key={list.name} id={list.name}>
<h2 key={"header"+list.name}>{list.name}</h2>
<ListForm update={lst.updateSaved} name={list.name}/>
</div>
</div>
)
});
var savedLists = this.state.savedLists.map(function(list) {
var list_data = list.data;
list_data.map(function(data) {
return (
<li>{data}</li>
)
});
return(
<div>
<h2>{list.name}</h2>
<ul>
{list_data}
</ul>
</div>
)
});
var save_msg;
if(savedLists.length == 0){
save_msg = 'No Saved Lists';
}else{
save_msg = 'Saved Lists';
}
return (
<div>
<TitleForm handleCreate={this.handleCreate} />
{lists}
<h2>{save_msg}</h2>
{savedLists}
</div>
)
}
});
ReactDOM.render(<List/>,document.getElementById('app'));
Мой HTML:
<div class="container">
<h1>Title</h1>
<div id="app" class="center"></div>
</div>
Ответы
Ответ 1
Существует множество способов создания unique keys
, самым простым методом является использование индекса при повторении массивов.
пример
var lists = this.state.lists.map(function(list, index) {
return(
<div key={index}>
<div key={list.name} id={list.name}>
<h2 key={"header"+list.name}>{list.name}</h2>
<ListForm update={lst.updateSaved} name={list.name}/>
</div>
</div>
)
});
Везде, где вы перебираете данные, здесь this.state.lists.map
вы можете передать вторую function(list, index)
параметра function(list, index)
на обратный вызов, и это будет его значение index
и оно будет уникальным для всех элементов в массив.
И тогда вы можете использовать его как
<div key={index}>
Вы можете сделать то же самое здесь
var savedLists = this.state.savedLists.map(function(list, index) {
var list_data = list.data;
list_data.map(function(data, index) {
return (
<li key={index}>{data}</li>
)
});
return(
<div key={index}>
<h2>{list.name}</h2>
<ul>
{list_data}
</ul>
</div>
)
});
редактировать
Однако, как указал пользователь Martin Dawson в комментарии ниже, это не всегда идеально.
Так что же тогда решение?
Многие
- Вы можете создать функцию для генерации уникальных ключей/идентификаторов/номеров/строк и использовать ее
- Вы можете использовать существующие пакеты npm, такие как uuid, uniqid и т.д.
- Вы также можете генерировать случайные числа, такие как
new Date().getTime();
и префикс его с чем-то из предмета, который вы итерируете, чтобы гарантировать его уникальность - Наконец, я рекомендую использовать уникальный идентификатор, который вы получаете из базы данных, если вы его получите.
Пример:
const generateKey = (pre) => {
return '${ pre }_${ new Date().getTime() }';
}
const savedLists = this.state.savedLists.map( list => {
const list_data = list.data.map( data => <li key={ generateKey(data) }>{ data }</li> );
return(
<div key={ generateKey(list.name) }>
<h2>{ list.name }</h2>
<ul>
{ list_data }
</ul>
</div>
)
});
Ответ 2
Для этого можно использовать пакет uuid
npm.
Общий модуль Nodejs
const uuidv1 = require('uuid/v1');
uuidv1(); // '10ba038e-48da-487b-96e8-8d3b99b6d18a
С ecma6:
import uuidv1 from 'uuid/v1';
uuidv1(); // '10ba038e-48da-487b-96e8-8d3b99b6d18a
Ответ 3
Как упоминалось ранее, использование индекса является антипаттерном. Лучший вариант, который я нашел до сих пор:
1) Импортировать "shorttid" из библиотеки React:
import shortid from 'shortid';
2) Используйте его в вашей петле, как показано ниже:
const controls = [];
collection.map(item => {
controls.push(<div className="column" key={'div-${shortid.generate()}'}>{item.text}</div>);
});
Надеюсь это поможет. Я только что опубликовал это, потому что было действительно трудно найти решение, подобное этому.
Ответ 4
Важно помнить, что React ожидает ключи STABLE, то есть вы должны назначать ключи один раз, и каждый элемент в вашем списке должен получать один и тот же ключ каждый раз, таким образом React может оптимизировать изменения ваших данных при согласовании виртуального DOM и принять решение какие компоненты нужно перерисовать. Итак, если вы используете UUID, вам нужно сделать это на уровне данных, а не на уровне UI.
Также имейте в виду, что для ключа можно использовать любую строку, которую вы хотите, поэтому вы часто можете объединять несколько полей в один уникальный идентификатор, например, ${username}_${timestamp}
может быть прекрасным уникальным ключом для строки в чате., например.
Ответ 5
Обновление ответа с v4 UUID
npm install uuid
-------------------------------------
const uuidv4 = require('uuid/v4');
uuidv4(); // ⇨ '10ba038e-48da-487b-96e8-8d3b99b6d18a'
or
import uuidv from 'uuid/v4';
uuidv4(); // '10ba038e-48da-487b-96e8-8d3b99b6d18a
Ответ 6
Не используйте этот return
$ {pre} _ $ {new Date(). GetTime()} ;
, Вместо этого лучше иметь индекс массива, потому что, хотя он и не идеален, таким образом вы, по крайней мере, получите некоторую согласованность между компонентами списка, а с новой новой функцией Date вы получите постоянную несогласованность. Это означает, что каждая новая итерация функции приведет к новому действительно уникальному ключу.
Уникальный ключ не означает, что он должен быть глобально уникальным, это означает, что он должен быть уникальным в контексте компонента, чтобы он не выполнял бесполезные повторные рендерингы все время. Сначала вы не почувствуете проблему, связанную с новой датой, но почувствуете это, например, если вам нужно вернуться к уже сформированному списку, и React начнет запутываться, потому что не знает, какой компонент изменился, а какой нет, что приводит к утечкам памяти, потому что, как вы уже догадались, в соответствии с вашим ключом Date каждый компонент изменился.
Теперь к моему ответу. Допустим, вы предоставляете список видео YouTube. Используйте идентификатор видео (arqTu9Ay4Ig) в качестве уникального идентификатора. Таким образом, если этот идентификатор не изменится, компонент останется прежним, но если это произойдет, React распознает, что это новое видео, и изменит его соответствующим образом.
Это не должно быть настолько строго, немного более расслабленный вариант - использовать заголовок, как уже указывал Эрез Хохман, или комбинацию атрибутов компонента (заголовок плюс категория), так что вы можете указать React проверить изменились они или нет.
отредактировал некоторые неважные вещи
Ответ 7
Я использую это:
<div key={+new Date() + Math.random()}>