我正在构建一个React组件,它接受JSON数据源并创建一个可排序的表。 每个动态数据行都有一个唯一的键分配给它,但我仍然得到一个错误:

数组中的每个子元素都应该有一个唯一的“key”道具。 检查TableComponent的渲染方法。

我的TableComponent渲染方法返回:

<table>
  <thead key="thead">
    <TableHeader columns={columnNames}/>
  </thead>
  <tbody key="tbody">
    { rows }
  </tbody>
</table>

TableHeader组件是单行,也有一个唯一的键赋给它。

行中的每一行都是由一个具有唯一键的组件构建的:

<TableRowItem key={item.id} data={item} columns={columnNames}/>

TableRowItem看起来是这样的:

var TableRowItem = React.createClass({
  render: function() {

    var td = function() {
        return this.props.columns.map(function(c) {
          return <td key={this.props.data[c]}>{this.props.data[c]}</td>;
        }, this);
      }.bind(this);

    return (
      <tr>{ td(this.props.item) }</tr>
    )
  }
});

是什么导致唯一键道具错误?


您应该为每个子元素以及子元素中的每个元素添加一个键。

这样React就可以处理最小的DOM更改。

在代码中,每个<TableRowItem key={项。id} data={item} columns={columnNames}/>试图在其中呈现一些没有键的子元素。

请看这个例子。

尝试从div的<b></b>元素中删除key={i}(并检查控制台)。

在本例中,如果我们没有给<b>元素一个键,并且我们只想更新对象。在city中,React需要重新渲染整个行,而不仅仅是元素。

代码如下:

const data = [
  { name: "Nuri", age: 28, city: "HO" },
  { name: "Talib", age: 82, city: "HN" },
  { name: "Jenny", age: 41, city: "IT" },
];

const ExampleComponent = React.createClass({
  render: function () {
    const infoData = this.props.info;
    return (
      <div>
        {infoData.map((object, i) => {
          return (
            <div className={"row"} key={i}>
              {[
                object.name,
                // remove the key
                <b className="fosfo" key={i}>
                  {" "}
                  {object.city}{" "}
                </b>,
                object.age,
              ]}
            </div>
          );
        })}
      </div>
    );
  },
});

React.render(<ExampleComponent info={data} />, document.body);

下面由@Chris发布的答案比这个答案更详细。

React文档中关于按键在协调中的重要性:按键


在迭代数组时要小心!!

这是一个常见的误解,使用数组中元素的下标是一种可以接受的抑制错误的方法,你可能熟悉:

Each child in an array should have a unique "key" prop.

然而,在许多情况下并非如此!这是一种反模式,在某些情况下可能导致不必要的行为。


理解关键道具

React使用关键道具来理解组件到dom元素的关系,然后将其用于协调过程。因此,关键字始终保持唯一是非常重要的,否则React很可能会混淆元素并变异出不正确的元素。同样重要的是,这些键在所有重渲染中保持静态,以保持最佳性能。

话虽如此,只要已知数组是完全静态的,就不总是需要应用上述方法。但是,只要可能,就鼓励应用最佳实践。

一个React开发者在GitHub上说:

密钥其实与性能无关,它更关乎身份(这反过来又会带来更好的性能)。随机分配和变化的值不是身份 在不知道你的数据是如何建模的情况下,我们无法(自动)提供密钥。如果你没有id,我建议你使用一些哈希函数 当我们使用数组时,我们已经有了内部键,但它们是数组的索引。当您插入一个新元素时,这些键是错误的。

简而言之,关键应该是:

唯一——键不能与同级组件的键相同。 静态-一个键不应该在渲染之间改变。


使用关键道具

根据上面的解释,仔细研究下面的示例,并在可能的情况下尝试执行推荐的方法。


坏(可能)

<tbody>
    {rows.map((row, i) => {
        return <ObjectRow key={i} />;
    })}
</tbody>

这可以说是React中迭代数组时最常见的错误。从技术上讲,这种方法并不是“错误的”,只是……“危险”,如果你不知道你在做什么。如果你正在迭代一个静态数组,那么这是一个完全有效的方法(例如,导航菜单中的链接数组)。但是,如果您正在添加、删除、重新排序或过滤项目,则需要小心。看看官方文件中的详细解释。

class MyApp extends React.Component { constructor() { super(); this.state = { arr: ["Item 1"] } } click = () => { this.setState({ arr: ['Item ' + (this.state.arr.length+1)].concat(this.state.arr), }); } render() { return( <div> <button onClick={this.click}>Add</button> <ul> {this.state.arr.map( (item, i) => <Item key={i} text={"Item " + i}>{item + " "}</Item> )} </ul> </div> ); } } const Item = (props) => { return ( <li> <label>{props.children}</label> <input value={props.text} /> </li> ); } ReactDOM.render(<MyApp />, document.getElementById("app")); <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> <div id="app"></div>

在这个代码片段中,我们使用了一个非静态数组,并且我们没有限制自己将其用作堆栈。这是一种不安全的方法(您将看到原因)。请注意,当我们向数组的开头添加项时(基本上是unshift),每个<input>的值保持不变。为什么?因为键不能唯一地标识每一项。

换句话说,一开始Item 1的key={0}。当我们添加第二个项目时,最上面的项目成为项目2,然后是项目1作为第二个项目。但是,现在Item 1的key={1}不再是key={0}了。相反,项目2现在有key={0}!!

因此,React认为<input>元素没有改变,因为键为0的Item总是在顶部!

那么,为什么这种方法有时是不好的呢?

这种方法只有在以某种方式筛选、重新排列数组或添加/删除项时才有风险。如果它总是静态的,那么使用它是完全安全的。例如,像["Home", "Products", "Contact us"]这样的导航菜单可以使用这种方法安全地迭代,因为您可能永远不会添加新的链接或重新排列它们。

简而言之,当你可以安全地使用索引作为键时:

数组是静态的,永远不会改变。 数组永远不会被筛选(显示数组的子集)。 数组永远不会被重新排序。 该数组用作堆栈或后进先出(LIFO)。换句话说,添加只能在数组的末尾进行(即push),并且只能删除最后一项(即pop)。

相反,如果在上面的代码片段中,将添加的项推到数组的末尾,则每个现有项的顺序将始终正确。


非常糟糕的

<tbody>
    {rows.map((row) => {
        return <ObjectRow key={Math.random()} />;
    })}
</tbody>

虽然这种方法可能会保证键的唯一性,但它总是会迫使react重新呈现列表中的每个项,即使这不是必需的。这是一个非常糟糕的解决方案,因为它极大地影响了性能。更不用说,如果Math.random()两次产生相同的数字,则不能排除键碰撞的可能性。

不稳定的键(如Math.random()生成的键)将导致不必要地重新创建许多组件实例和DOM节点,这可能导致子组件的性能下降和状态丢失。


很好

<tbody>
    {rows.map((row) => {
        return <ObjectRow key={row.uniqueId} />;
    })}
</tbody>

这可以说是最好的方法,因为它使用的属性对于数据集中的每个项都是唯一的。例如,如果行包含从数据库获取的数据,则可以使用表的主键(通常是一个自动递增的数字)。

选择键的最佳方法是使用一个字符串,该字符串在其兄弟姐妹中唯一地标识一个列表项。大多数情况下,您会使用数据中的id作为键


Good

componentWillMount() {
  let rows = this.props.rows.map(item => { 
    return {uid: SomeLibrary.generateUniqueID(), value: item};
  });
}

...

<tbody>
    {rows.map((row) => {
        return <ObjectRow key={row.uid} />;
    })}
</tbody>

This is also a good approach. If your dataset does not contain any data that guarantees uniqueness (e.g. an array of arbitrary numbers), there is a chance of a key collision. In such cases, it is best to manually generate a unique identifier for each item in the dataset before iterating over it. Preferably when mounting the component or when the dataset is received (e.g. from props or from an async API call), in order to do this only once, and not each time the component re-renders. There are already a handful of libraries out there that can provide you such keys. Here is one example: react-key-index.


警告:数组或迭代器中的每个子元素都应该有一个唯一的“key”道具。

这是一个警告,因为我们要迭代的数组项需要一个唯一的相似性。

React将迭代组件渲染处理为数组。

更好的解决方法是为你要遍历的数组项提供索引。例如:

class UsersState extends Component
    {
        state = {
            users: [
                {name:"shashank", age:20},
                {name:"vardan", age:30},
                {name:"somya", age:40}
            ]
        }
    render()
        {
            return(
                    <div>
                        {
                            this.state.users.map((user, index)=>{
                                return <UserState key={index} age={user.age}>{user.name}</UserState>
                            })
                        }
                    </div>
                )
        }

index是React内置的道具。


只需将唯一键添加到组件

data.map((marker)=>{
    return(
        <YourComponents 
            key={data.id}     // <----- unique key
        />
    );
})

这是一个警告,但解决这个问题将使反应渲染更快,

这是因为React需要唯一地标识列表中的每个项。假设在React Virtual DOM中,如果列表中某个元素的状态发生了变化,那么React需要找出哪个元素发生了变化,以及它需要在DOM中的哪个位置发生变化,以便浏览器的DOM与React Virtual DOM保持同步。

作为解决方案,只需为每个li标记引入一个键属性。该键对于每个元素都应该是唯一的值。


检查:key = undef !!

你也得到了警告信息:

Each child in a list should have a unique "key" prop.

如果你的代码是完全正确的,但是如果打开

<ObjectRow key={someValue} />

someValue未定义!!请先检查一下这个。你可以节省时间。


var TableRowItem = React.createClass({
  render: function() {

    var td = function() {
        return this.props.columns.map(function(c, i) {
          return <td key={i}>{this.props.data[c]}</td>;
        }, this);
      }.bind(this);

    return (
      <tr>{ td(this.props.item) }</tr>
    )
  }
});

这样问题就解决了。


react中定义唯一键的最佳解决方案: 在映射内部,初始化名称post,然后用key={post定义键。Id}或者在我的代码中,你看到我定义了名称item,然后我定义key by key={item. Id}:

< div className = "容器" > {职位。地图(项= > ( <div className="card border-primary mb-3" key={item.id}> . < div className = " card-header " > {item.name} < / div > <div className="card-body" > < h4 className = " card-title " > {item.username} < / h4 > < p className = "卡片文本" > {item.email} < / p > < / div > < / div > )} < / div >


这可能对某些人有帮助,也可能没有,但它可能是一个快速的参考。这也类似于上面给出的所有答案。

我有很多使用下面结构生成列表的位置:

return (
    {myList.map(item => (
       <>
          <div class="some class"> 
             {item.someProperty} 
              ....
          </div>
       </>
     )}
 )
         

经过一些尝试和错误(以及一些挫折)后,向最外层的块添加一个键属性解决了这个问题。另外,注意<>标记现在被<div>标记取代。

return (
  
    {myList.map((item, index) => (
       <div key={index}>
          <div class="some class"> 
             {item.someProperty} 
              ....
          </div>
       </div>
     )}
 )

当然,在上面的例子中,我一直天真地使用迭代索引(index)来填充键值。理想情况下,您应该使用列表项唯一的内容。


我遇到这个错误消息,因为<></>被返回数组中的一些项目,而不是null需要返回。


在ReactJS中,如果你要渲染一个元素数组,那么每个元素都应该有一个唯一的键。通常这种情况会产生一个列表。

例子:

function List() {
  const numbers = [0,1,2,3];
 
  return (
    <ul>{numbers.map((n) => <li> {n} </li>)}</ul>
  );
}

 ReactDOM.render(
  <List />,
  document.getElementById('root')
);

在上面的例子中,它使用li标签创建了一个动态列表,所以由于li标签没有唯一键,所以它显示了一个错误。

固定后:

function List() {
  const numbers = [0,1,2,3];
 
  return (
    <ul>{numbers.map((n) => <li key={n}> {n} </li>)}</ul>
  );
}

 ReactDOM.render(
  <List />,
  document.getElementById('root')
);

当你没有唯一键时使用map的替代解决方案(react eslint不推荐这样做):

function List() {
  const numbers = [0,1,2,3,4,4];
 
  return (
    <ul>{numbers.map((n,i) => <li key={i}> {n} </li>)}</ul>
  );
}

 ReactDOM.render(
  <List />,
  document.getElementById('root')
);

实例:https://codepen.io/spmsupun/pen/wvWdGwG


我有一个唯一的键,只需要像这样传递它作为道具:

<CompName key={msg._id} message={msg} />

这个页面很有帮助:

https://reactjs.org/docs/lists-and-keys.html#keys


当你对呈现的项目没有稳定的id时,你可以使用项目索引作为关键字作为最后的手段:

const todoItems = todos.map((todo, index) =>
// Only do this if items have no stable IDs
   <li key={index}>
      {todo.text}
   </li>
);

请参考列表和键-反应


在我的例子中,将id设置为tag

<tbody key={i}>

问题解决了。


If you are getting error like :

> index.js:1 Warning: Each child in a list should have a unique "key" prop.

Check the render method of `Home`. See https://reactjs.org/link/warning-keys for more information.

Then Use inside map function like:

  {classes.map((user, index) => (
              <Card  **key={user.id}**></Card>
  ))}`enter code here`

您应该为tbody where的每个子键使用唯一的值

该值不能与其同级值相同 不应该在渲染之间改变

例如,键值可以是数据库id或UUID(通用唯一标识符)。

这里的键是手动处理的:

<tbody>
  {rows.map((row) => <ObjectRow key={row.uuid} />)}
</tbody>

你也可以让React使用React. children . toarray来处理键

<tbody>
  {React.Children.toArray(rows.map((row) => <ObjectRow />))}
</tbody>

我也遇到过类似的问题,但不确切。尝试了所有可能的解决方案,都无法摆脱这个错误

数组中的每个子元素都应该有一个唯一的“key”道具。

然后我尝试在不同的本地主机上打开它。我不知道怎么回事,但它奏效了!


这是一个简单的例子,我使用了一个react条件&&先映射,在我已经添加了用户id键,以确保它是唯一的

 <tbody>
                                    {users &&
                                    users.map((user) => {
                                        return <tr key={user._id}>
                                            <td>{user.username}</td>
                                            <td><input
                                                name="isGoing"
                                                type="checkbox"
                                                checked={user.isEnabled}
                                                onChange={handleInputChangeNew}/></td>
                                            <td>{user.role.roleTitle} - {user.role.department.departmentName}</td>
                                            {/*<td className="text-right">
                                                    <Button>
                                                        ACTION
                                                    </Button>
                                                </td>*/}
                                        </tr>
                                    })
                                    }


                                    </tbody>

我不做详细的解释,但这个答案的关键是“关键” 只需将key属性放在标签中,并确保每次迭代时都赋予它唯一的值

#确保键的值不与其他值冲突

例子

<div>
        {conversation.map(item => (
          <div key={item.id  } id={item.id}>
          </div>
        ))}
      </div>

conversation是一个数组,如下所示:

  const conversation = [{id:"unique"+0,label:"OPEN"},{id:"unique"+1,label:"RESOLVED"},{id:"unique"+2,label:"ARCHIVED"},
   ]

列表中的每个子元素都应该有一个唯一的“key”道具。

通过在呈现元素中的key属性中声明index值来解决。

App.js组件

import Map1 from './Map1';

const arr = [1,2,3,4,5];

const App = () => {
  return (
    <>
     
     <Map1 numb={arr} />     

    </>
  )
}

export default App

Map.js组件

const Map1 = (props) => {

    let itemTwo = props.numb;
    let itemlist = itemTwo.map((item,index) => <li key={index}>{item}</li>)

    return (
        <>        
        <ul>
            <li style={liStyle}>{itemlist}</li>
        </ul>
        </>
    )
}

export default Map1

您的密钥应该是唯一的。就像一个唯一的id。你的代码应该是这样的

<div>
 {products.map(product => (
   <Product key={product.id}>
    </Product>
    ))}
  </div>

如果我们有数组对象数据。然后我们绘制地图来显示数据。并传递唯一的id (key = {product。Id})因为浏览器可以选择唯一的数据。

example : [
    {
        "id": "1",
        "name": "walton glass door",
        "suplier": "walton group",
        "price": "50000",
        "quantity": "25",
        "description":"Walton Refrigerator is the Best Refrigerator brand in bv 
         Bangladesh "
    },
    {
        
        "id": "2",
        "name": "walton glass door",
        "suplier": "walton group",
        "price": "40000",
        "quantity": "5",
        "description":"Walton Refrigerator is the Best Refrigerator brand in 
         Bangladesh "
    },
}

现在我们映射数据并传递唯一id:

{
    products.map(product => <product product={product} key={product.id} 
    </product>)
}

下面是React文档,它们很好地解释了Key属性的使用,Key应该在父组件中定义,不应该在子组件中使用。反应文档


一个直观的解释。

(数组的)key=index的错误方式

正如你所看到的,标签3、标签2和标签1都被重新渲染了(在元素面板中闪烁)。

正确的方法是key=uniqueId

只有顶部的新元素会闪烁(重新渲染)。


我认为在处理表(或类似的例子)时,为了重用性,应该将创建的唯一键从父组件传递给子组件。

因为如果你正在创建一个表,这意味着你正在从父表传递数据。如果你赋值key={row.name},可能当前数据有name属性,但如果你想在其他地方使用这个表组件,你假设在你传递的每一行数据中,你都有name属性。

由于工程师将在父组件中准备数据,因此工程师应该基于这些数据创建一个键函数。

const keyFunc = (student) => {
    return student.id;
  }; 

在这种情况下,工程师知道它正在发送什么数据,它知道每一行都有唯一的id属性。也许在不同的数据集中,数据集是股票价格它没有id属性,只有符号

 const keyFunc = (stock) => {
        return stock.symbol;
      }; 

这个keyFunc应该作为道具传递给子组件,以保证可重用性和唯一性。


根据React文档,每一行/项都应该有一个唯一的键。

键帮助React识别哪些项已经更改、添加或删除。

就我个人而言,我更喜欢使用加密接口来生成一个随机UUID: (crypto在vanilla-js中是内置的)

const numbers = [1, 2, 3, 4, 5];

const listItems = numbers.map((number) =>
  <li key={crypto.randomUUID()}>item {number}
  </li>
);

当你创建一个没有特殊key属性的元素列表时,React中会出现“列表中的每个子元素都应该有一个唯一的“key”道具”警告。必须为循环中的每个元素分配键,以便为React中的元素提供稳定的标识。

我们可以将对象的id属性设置为唯一键。

export default function App() {
      const posts = [
{ id: 1, title: "First "},
{ id: 2, title: "Second" },
{ id: 3, title: "Third" }
 ];
 return (
<div>
    <ul>
        {posts.map(value => 
            <li key={value.id}>{value.title}</li>
        )}
    </ul>
</div>
 );}


//simple way

//if u using ant design remove the empty fragment...

//worng ans---> change to following crt ans

export default function App() {
      const posts = [
{ id: 1, title: "First "},
{ id: 2, title: "Second" },
{ id: 3, title: "Third" }
 ];
 {fields.map((field,index)=>{
return(
  <> //empty fragment
   <Row key={index}>
    <Col span={6}>hello</Col>
   </Row>
  </>
)
})}

 //correct ans
//remove the empty fragments after solve this key.prop warning problem
export default function App() {
      const posts = [
{ id: 1, title: "First "},
{ id: 2, title: "Second" },
{ id: 3, title: "Third" }
 ];
 {fields.map((field,index)=>{
return(
  <> //empty fragment
   <Row key={index}>
    <Col span={6}>hello</Col>
   </Row>
  </>
)
})}

使用UUID lib创建一个随机UUID: 执行NPM install uuid命令

import { v4 as uuid } from "uuid";

array.map((item) =>
  <li key={uuid()}>{item}
  </li>
);

在使用Mongo数据的情况下,您可以使用_id属性

arr.map((cell) =>
  <li key={cell._id}>{cell}
  </li>
);