【问题标题】:I am getting a unique key prop warning when i have a unique key当我有唯一键时,我会收到唯一键道具警告
【发布时间】:2019-03-22 09:30:23
【问题描述】:

我是 React 新手,但我知道唯一键的主要概念。但是,我收到了警告。

下面我有一个项目组件:

class Item extends Component {
    state = {}

    render() { 
        return ( 
            <React.Fragment>
                {this.props.item.todo}
            </React.Fragment>
        );
    }
}

下面是我的项目组件,我有唯一的键:

render() { 
    const { items } = this.props;
    return ( 
        items.map(item=>
            <React.Fragment>
                <Item key={item.todo} item={item} />
            </React.Fragment>
        )    
    );
}

我收到了警告!

【问题讨论】:

    标签: javascript html reactjs reactive-programming


    【解决方案1】:

    正如其他人所说,您需要在顶部元素上设置key,在您的情况下为Fragment。但我会改变键值。我不知道您的 item.todo 中有哪些类型的数据,但仅将密钥设置为 item.todo 的值可能会有问题。我会解释的。

    一个键应该只在其兄弟中是唯一的

    react.org 关于列表和键的文档完美地总结了这一点,所以我不会以其他方式解释。它在下面这样说。

    数组中使用的键在它们的兄弟中应该是唯一的。但是,它们不需要是全球唯一的。当我们生成两个不同的数组时,我们可以使用相同的键:

    (注意:不需要是有意义的数据)。

    密钥应该是稳定的

    这意味着渲染之间的键不应该改变,所以不要使用Math.random()一些人们认为使用它会很好。

    为什么以上内容很重要?

    在您的数据中,如果两个 items.todo 是相同的值,那么它将破坏上述内容。您的密钥不会是唯一的。这可能会导致不必要的重新渲染导致性能问题。

    我建议使用一个键,其值为items.todo 和地图的index。这样,如果您对items.todo 确实具有相同的值,则添加索引将使键唯一。考虑到这一点,我会写你的 sn-p。

    render() { 
      const { items } = this.props;
    
      return ( 
        items.map((item, index) => (
          <React.Fragment key={item.todo + index}>
            <Item item={item} />
          </React.Fragment>
        ))
      );
    }
    

    这里是 list and keys 上 react.org 文档的链接,也是 fragments 上 react.org 文档的链接。两者都提供了示例和有用的信息。它们是一本好书,我强烈推荐。

    我还注意到,您使用的是React.Fragment,但随后您只使用Component 声明了您的类。你可以做我假设你已经为Component 做的事情并解构Fragement。如下所示:

    import React, { Component, Fragment } from 'react';
    

    所以你的 sn-p 更干净一点,如下所示:

    items.map((item, index) => (
      <Fragment key={item.todo + index}>
        <Item item={item} />
      <Fragment>
    ))
    

    【讨论】:

      【解决方案2】:

      您需要将key 道具保留在顶部元素上,正如@Tholle 在答案中建议的那样。但在这里,我要建议的是不要使用&lt;React.Fragment&gt;

      items.map(item=>
         <Item key={item.todo} item={item} />
      )
      

      当您不想使用&lt;div /&gt;&lt;p /&gt; 等包装器包装元素时,使用Fragment。由于您拥有&lt;Item /&gt; 组件,因此无需使用Fragment

      如果您可以使用Fragment,以下是示例:

      items.map(item=>
         <React.Fragment key={item.todo}>
           <Item item={item} />
           <p>Another Component...</p>
         </React.Fragment>
      )
      

      但是很抱歉,如果您使用 Fragment 的别名:&lt;&gt;&lt;/&gt; 不支持 key 属性。它应该明确设置,根本没有任何道具。如果你需要使用key,你需要用一个元素包装它们:

      items.map(item=>
         <div key={item.todo}>
           <Item item={item} />
           <p>Another Component...</p>
         </div>
      )
      

      这将是无效的:

      items.map(item=>
         <key={item.todo}>
           <Item item={item} />
           <p>Another Component...</p>
         </>
      )
      

      【讨论】:

        【解决方案3】:

        您需要将key 属性放在顶部元素上,即React.Fragment 而不是Item

        items.map(item=>
          <React.Fragment key={item.todo}>
            <Item item={item} />
          </React.Fragment>
        )    
        

        【讨论】:

          【解决方案4】:

          为 React.Fragment 提供密钥

          render() { 
            const { items } = this.props;
          
            return ( 
              items.map(item =>
                <React.Fragment key={item.todo}>
                  <Item item={item} />
                </React.Fragment>
              )
            );
          }
          

          【讨论】:

            【解决方案5】:

            更好的解决方案是使用shortid npm 包。它被描述为“非常短的非顺序 url 友好的唯一 id 生成器。”

            使用数组索引作为键是一种反模式。在this article 上阅读更多信息。 ESLINT 也可以防止这种情况 -> Prevent usage of Array index in keys (react/no-array-index-key)

            这是我的使用方法。

            npm install shortid
            
            
            import shortid from 'shortid'
            
            // using https://www.npmjs.com/package/shortid to prevent duplicate fragment keys
            names.map(name => {
                return (
                    <Fragment key={`fragment-${id}-${shortid.generate()}`}>
                        Hello, {name}!
                    </Fragment>
                )
            });
            

            【讨论】:

            • 通过在 map 中使用 generate 函数,您将在每次重新渲染时为同一元素使用不同的键,这不是 React 所期望的。在此处查看文档:reactjs.org/docs/lists-and-keys.html#keys
            猜你喜欢
            • 1970-01-01
            • 2019-01-29
            • 2022-07-12
            • 2021-12-02
            • 2019-10-12
            • 1970-01-01
            • 2021-05-27
            • 1970-01-01
            • 2021-11-29
            相关资源
            最近更新 更多