Feuermurmel
Feuermurmel

Reputation: 9922

Avoid having to specify a key for list of very simple elements

I'm working on an application written using JSX and React where the content of some elements are not very structured but still generated procedurally. An example could be placing strings from a list onto individual lines:

function getRow(items) {
     let elements = [];

     // Procedurally generate the list of elements.
     for (let i of items) {
          if (elements.length > 0) {
                // Add line breaks between the line.
                elements.push(<br />);
          }

          elements.push(i);
     }

     return <tr>
          {/* More elements here. */}
          <td>
                {/* Place the element into the cell. */}
                {elements}
          </td>
          {/* More elements here. */}
     </tr>;
}

Other examples would be adding some styling based on state or context but the elements are never nested or themselves complex in nature. The problem is that with this code, React displays a warning about missing key attributes on the elements. This happens because the elements are placed into the JSX tree as a list and React is trying to help me write efficient code.

Warning: Each child in an array or iterator should have a unique "key" prop. ...

Of course I could just add those key attributes to each element but it gets very cumbersome when multiple elemnts are generated per iterated item or there's no iteration index to base the keys of. In the cases I'm looking at, it does not seem beneficial to add those keys. I would not be surprised if in these cases just replacing all elements each time one of them changes would actually be faster than React's logic based on key attributes.

Is there a clean way to either disable the warning from React in these cases or is there a different way of inserting the elements into the JSX tree which does not trigger the warning?

Upvotes: 0

Views: 160

Answers (3)

Hagbourne
Hagbourne

Reputation: 98

This might not answer the "how do I disable" question, but I suggest a way to deal with the problem of the lacking keys rather than the symptoms :-P ..there are clean ways of generating the keys programatically. Try something like this:

function getRow(items) {
    const elements = [];
    items.map((item, index) => {
        elements.push(
          <tr key={'row-' + index}>
             <td>{item.value1}</td>
             <td>{item.value2}</td>
             <td>{item.value3}</td>
          </tr>
        );
    });
    return elements;
}

Upvotes: 0

Michael Peyper
Michael Peyper

Reputation: 6944

If you really don't know what components will be in items when trying to build elements and absolutely can't use a sensible key or add index based keys when creating the components, you can use this to remove the warning:

function getRow(items) {
     let elements = [];

     // Procedurally generate the list of elements.
     for (let i of items) {
          if (elements.length > 0) {
                // Add line breaks between the line.
                elements.push(<br />);
          }

          elements.push(i);
     }

     // Ensure there is a unique key for all elements
     elements = elements.map((e, i) => React.cloneElement(e, { key: i }))

     return <tr>
          {/* More elements here. */}
          <td>
                {/* Place the element into the cell. */}
                {elements}
          </td>
          {/* More elements here. */}
     </tr>;
}

This should only be used as an absolute last resort and I make no guarantees on it's performance as it is cloning every element to give it a key. It will also override a key already on an element, so any benefit from having a sensible key on some elements will be lost.

Upvotes: 1

abhirathore2006
abhirathore2006

Reputation: 3745

Whenever you are returning array of items you need to specify a key so React can distinguish between them, its not so hard because in every loop/map have unique index or key field which you can use as key, you can prefix them so two keys in same loop also won't confilct

[1,2,3].forEach((item,index)=>{
  arr.push(<div key={`forEachloop-${i}`></div>)
  if(somecondition == true){
  /** prefix for making key unique **/
  arr.push(<div key={`forEachloop-condition-${i}`></div>)
  }
}

[1,2,3].map((item,index)=>{
  return (<div key={`forEachloop-${i}`></div>)
}

Upvotes: 0

Related Questions