Search code examples
javascriptreactjs

Understanding unique keys for array children in React.js


I'm building a React component that accepts a JSON data source and creates a sortable table.
Each of the dynamic data rows has a unique key assigned to it but I'm still getting an error of:

Each child in an array should have a unique "key" prop.
Check the render method of TableComponent.

My TableComponent render method returns:

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

The TableHeader component is a single row and also has a unique key assigned to it.

Each row in rows is built from a component with a unique key:

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

And the TableRowItem looks like this:

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

What is causing the unique key prop error?


Solution

  • You should add a key to each child as well as each element inside children.

    This way React can handle the minimal DOM change.

    In your code, each <TableRowItem key={item.id} data={item} columns={columnNames}/> is trying to render some children inside them without a key.

    Check this example.

    Try removing the key={i} from the <b></b> element inside the div's (and check the console).

    In the sample, if we don't give a key to the <b> element and we want to update only the object.city, React needs to re-render the whole row vs just the element.

    Here is the code:

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

    The answer posted by @Chris at the bottom goes into much more detail than this answer.

    React documentation on the importance and usage of keys: Keys