如何为 React 元素创建唯一键?

新手上路,请多包涵

我正在制作一个 React 应用程序,它允许您创建一个列表并保存它,但 React 一直在警告我,我的元素没有唯一的 key prop(元素 List/ListForm)。我应该如何为用户创建的元素创建一个唯一的 key prop?下面是我的反应代码

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>

原文由 user1775500 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.4k
2 个回答

有很多方法可以创建 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) 也传递给回调,这将是它的 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 在下面的评论中指出的那样,这并不总是理想的。

那么解决方案是什么呢?

许多

  • 您可以创建一个函数来生成唯一的键/ID/数字/字符串并使用它
  • 您可以使用现有的 npm 包,如 uuiduniqid
  • 您还可以生成随机数,例如 new Date().getTime(); 并在其前面加上您正在迭代的项目中的某些内容,以保证其唯一性
  • 最后,我建议使用从数据库中获得的唯一 ID,如果你得到它。

例子:

 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>
    )
});

原文由 Dhruv Kumar Jha 发布,翻译遵循 CC BY-SA 3.0 许可协议

重要的是要记住,React 需要 STABLE 键,这意味着您应该分配一次键,并且列表中的每个项目每次都应该收到相同的键,这样 React 可以在协调虚拟 DOM 时围绕您的数据更改进行优化并决定哪些组件需要重新渲染。因此,如果您使用 UUID,则需要在数据级别而不是 UI 级别执行此操作。

另外请记住,您可以使用任何您想要的字符串作为密钥,因此您通常可以将多个字段组合成一个唯一 ID,例如 ${username}_${timestamp} 可以是聊天中一行的一个很好的唯一密钥,例如例子。

原文由 Erez Hochman 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进