我正在制作一个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'));
Run Code Online (Sandbox Code Playgroud)
我的HTML:
<div class="container">
<h1>Title</h1>
<div id="app" class="center"></div>
</div>
Run Code Online (Sandbox Code Playgroud)
Dhr*_*Jha 36
您可以通过多种方式创建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>
)
});
Run Code Online (Sandbox Code Playgroud)
无论你在哪里砍掉数据,在这里this.state.lists.map
,你都可以将第二个参数传递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>
)
});
Run Code Online (Sandbox Code Playgroud)
那么解决方案呢?
许多
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>
)
});
Run Code Online (Sandbox Code Playgroud)
Ere*_*man 17
重要的是要记住,React期望使用STABLE密钥,这意味着您应该分配一次密钥,并且列表中的每个项目每次都应接收相同的密钥,这样,React可以在协调虚拟DOM并决定哪些组件需要重新渲染。因此,如果您使用的是UUID,则需要在数据级别而不是UI级别执行。
还要记住,您可以将任何想要的字符串用作键,因此您通常可以将多个字段组合为一个唯一的ID,例如,${username}_${timestamp}
可以作为聊天中一行的唯一键。
Dan*_*ana 15
正如反应文档所解释的,不建议对键使用索引“ 如果项目的顺序可能会更改。这会对性能产生负面影响,并可能导致组件状态出现问题 ”。在这种情况下,我建议使用一种称为shortid的工具。
1)使用NPM / YARN安装软件包:
npm install shortid --save
Run Code Online (Sandbox Code Playgroud)
2)导入要使用的类文件:
import shortid from 'shortid';
Run Code Online (Sandbox Code Playgroud)
2)生成新ID的命令是shortid.generate()。
3)范例:
renderDropdownItems = (): React.ReactNode => {
const { data, isDisabled } = this.props;
const { selectedValue } = this.state;
const dropdownItems: Array<React.ReactNode> = [];
if (data) {
data.forEach(item => {
dropdownItems.push(
<option value={item.value} key={shortid.generate()}>
{item.text}
</option>
);
});
}
return (
<select
value={selectedValue}
onChange={this.onSelectedItemChanged}
disabled={isDisabled}
>
{dropdownItems}
</select>
);
};
Run Code Online (Sandbox Code Playgroud)
希望这可以帮助。我刚刚发布了这篇文章,因为很难找到这样的解决方案。
Vin*_*rma 10
您可以利用React.Children API:
const { Children } = React;
const DATA = [
'foo',
'bar',
'baz',
];
const MyComponent = () => (
<div>
{Children.toArray(DATA.map(data => <p>{data}</p>))}
</div>
);
ReactDOM.render(<MyComponent />,document.getElementById("root"));
Run Code Online (Sandbox Code Playgroud)
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Run Code Online (Sandbox Code Playgroud)
可以使用uuid
npm包.
Nodejs常用模块
const uuidv1 = require('uuid/v1');
uuidv1(); // '10ba038e-48da-487b-96e8-8d3b99b6d18a
Run Code Online (Sandbox Code Playgroud)
使用ecma6:
import uuidv1 from 'uuid/v1';
uuidv1(); // '10ba038e-48da-487b-96e8-8d3b99b6d18a
Run Code Online (Sandbox Code Playgroud)
不要使用此return
$ {} _ $ {new Date()。getTime()} ;
。最好使用数组索引而不是数组索引,因为即使它不理想,那样的话,至少也可以使列表组件之间保持一定的一致性,而使用新的新Date函数,您将获得恒定的不一致。这意味着该函数的每次新迭代都将导致一个新的真正唯一的键。
唯一键并不意味着它必须是全局唯一的,它意味着它在组件的上下文中必须是唯一的,因此它不会一直无用地重新渲染。您最初不会感觉到与新Date相关的问题,但是会感觉到它的发生,例如,如果您需要返回到已渲染的列表,并且React开始感到困惑,因为它不知道哪个组件发生了更改以及哪个组件发生了更改否则,会导致内存泄漏,因为根据您的Date键,您猜到了每个组件都发生了更改。
现在我的答案。假设您要渲染一个YouTube视频列表。使用视频ID(arqTu9Ay4Ig)作为唯一ID。这样,如果该ID不变,则组件将保持不变,但是如果保持不变,React将识别出它是一个新的Video并相应地对其进行更改。
不必那么严格,稍微放松一点的变体就是使用标题,例如Erez Hochman已经指出的那样,或者使用组件属性的组合(标题加类别),因此您可以告诉React检查是否已更改。
编辑了一些不重要的东西
添加 2021 年最新解决方案...
我发现该项目nanoid提供了独特的字符串 id,可以用作密钥,同时速度又快又非常小。
安装使用后npm install nanoid
,使用如下:
import { nanoid } from 'nanoid';
// Have the id associated with the data.
const todos = [{id: nanoid(), text: 'first todo'}];
// Then later, it can be rendered using a stable id as the key.
const todoItems = todos.map((todo) =>
<li key={todo.id}>
{todo.text}
</li>
)
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
69262 次 |
最近记录: |