当前位置: 首页 > 知识库问答 >
问题:

如何为元素创建唯一键?

松越
2023-03-14

我正在制作一个React应用程序,允许你制作一个列表并保存它,但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'));

我的超文本标记语言:

<div class="container">
    <h1>Title</h1>
    <div id="app" class="center"></div>
</div>

共有3个答案

令狐和裕
2023-03-14

键有助于识别哪些项已更改/添加/删除,哪些项应提供给数组中的元素,以便为元素提供稳定的标识。

考虑到这一点,基本上有以下三种不同的策略:

  1. 静态元素(不需要保持html状态(焦点、光标位置等)

正如React文档所解释的,我们需要为元素提供稳定的标识,因此,仔细选择最适合您需要的策略:

正如我们在React文档中看到的,不建议使用键索引“如果项的顺序可能更改。这可能会对性能产生负面影响,并可能导致组件状态问题”。

对于表、列表等静态元素,我建议使用名为shortid的工具。

1)使用NPM/YARN安装软件包:

npm install shortid --save

2) 在要使用的类文件中导入:

import shortid from 'shortid';

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

重要提示:由于React Virtual DOM依赖于键,使用shortid,每次重新呈现元素时,都将创建一个新键,元素将失去其html状态,如焦点或光标位置。在决定如何生成密钥时,请考虑这一点,因为只有当您构建的元素不会像列表或只读字段那样改变它们的值时,上述策略才是有用的。

如果元素是可排序的,并且您具有该项的唯一ID,请将其与一些额外的字符串组合(以防您需要在一个页面中有两次相同的信息)。这是最推荐的方案。

例子:

  renderDropdownItems = (): React.ReactNode => {
    const elementKey:string = 'ddownitem_'; 
    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={${elementKey}${item.id}}>
            {item.text}
          </option>
        );
      });
    }

    return (
      <select
        value={selectedValue}
        onChange={this.onSelectedItemChanged}
        disabled={isDisabled}
      >
        {dropdownItems}
      </select>
    );
  };

最后,对于可编辑(但不可排序)字段(如输入),您可以使用一些索引和一些起始文本作为元素键,但不能重复。

例子:

  renderDropdownItems = (): React.ReactNode => {
    const elementKey:string = 'ddownitem_'; 
    const { data, isDisabled } = this.props;
    const { selectedValue } = this.state;
    const dropdownItems: Array<React.ReactNode> = [];

    if (data) {
      data.forEach((item:any index:number) => {
        dropdownItems.push(
          <option value={item.value} key={${elementKey}${index}}>
            {item.text}
          </option>
        );
      });
    }

    return (
      <select
        value={selectedValue}
        onChange={this.onSelectedItemChanged}
        disabled={isDisabled}
      >
        {dropdownItems}
      </select>
    );
  };

希望这能有所帮助。

陆文博
2023-03-14

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

还请记住,您可以使用任意字符串作为键,因此您通常可以将多个字段组合成一个唯一的ID,例如,${username}{u${timestamp}可以是聊天中一行的一个很好的唯一键。

杜砚
2023-03-14

有许多方法可以创建唯一键,最简单的方法是在迭代数组时使用索引。

实例

    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。状态名单。映射,您还可以将第二个参数函数(列表,索引)传递给回调函数,这将是它的索引值,并且对于数组中的所有项都是唯一的。

然后你可以像这样使用它

<代码>

你也可以在这里做同样的事情

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

那么解决办法是什么呢?

许多的

  • 您可以创建一个函数来生成唯一的键/id/数字/字符串,并使用它
  • 您可以使用现有的npm包,如uuid,uniqid等
  • 您还可以生成随机数,如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>
    )
});
 类似资料:
  • 问题内容: 我正在制作一个React应用程序,该应用程序允许您创建列表并保存它,但是React一直警告我我的元素没有唯一的键道具(元素List / ListForm)。如何为用户创建的元素创建唯一的键道具?下面是我的React代码 我的HTML: 问题答案: 您可以通过多种方式创建,最简单的方法是在迭代数组时使用索引。 例 无论您将数据放在何处,都可以在此处将第二个参数传递 给回调,这将是它的值,

  • 我正在尝试在php中创建以下元素,以创建我们的一个客户所需的xml。 每件事都很好,但我不知道如何创建以下元素 我已经尝试了几种方法,但仍然无法正确生成上述示例 有人能送我上路吗? 这是我的代码

  • 问题内容: 在下面的示例中,我希望所有元素都是元组,为什么当元组仅包含单个字符串时,它会转换为字符串? 问题答案: 因为前两个元素不是元组;他们只是字符串。括号不会自动使它们成为元组。你必须在字符串后添加一个逗号,以指示python它应该是一个元组。 要修复示例代码,请在此处添加逗号: 从Python文档: 一个特殊的问题是包含0或1项的元组的构造:语法具有一些额外的怪癖来容纳这些项。空元组由一对

  • 有没有一种方法,每当I$push monodb数组中的新元素时,都会向它添加一个普通的_id?我记得mongoose是自动执行类似操作的,但现在我使用mongodb的原生js,它似乎没有插入任何id。 示例: 执行时,messages数组应具有常规的_id字段、message和date。目前它只创建消息和日期。

  • 问题内容: 有没有办法只在底部放阴影?我有一个菜单,彼此相邻有2张图像。我不想要正确的阴影,因为它会重叠正确的图像。我不喜欢为此使用图像,因此有一种方法可以将其仅放置在底部,例如: 或类似的? 问题答案: 更新4 与更新3相同,但具有现代的CSS(=较少的规则),因此不需要在伪元素上进行特殊定位。 更新3 我以前所有的答案都一直在使用额外的标记来创建此效果,而这并不是必需的。我认为这是一种 更 清

  • 我有一本空字典。名称:它将具有值为列表的键。 从一个单独的迭代中,我获得一个键(例如:)和一个项(一个元组),以放置在的值列表中。 如果此键已存在,我想附加此项。如果这个键不存在,我想用一个空列表创建它,然后附加到它,或者只是用一个元组创建它。 将来,当这个键再次出现时,由于它存在,我希望再次追加该值。 我的代码包括: 获取密钥和值。 查看中是否存在非密钥。 如果不创建: 之后: 这是做这件事的方