0

Is there a chance I can filter out items with JavaScript and have them being checked for null and avoid the unique "key" property warning? So far, for the following code:

{ menuItems.filter((item) => item !== null) }

... there is a small warning: Each child in a list should have a unique "key" prop.

Shared User
  • 105
  • 9

1 Answers1

1

To answer the question main question, yes, there is a way you can check and it would be by using the filter item.

Also, an alternative as to why you are still getting that warning despite the code looking correct. May be simply because your key is not unique.

Example 1:

Consider you have the following list of items:

const menuItems = ['a', 'b', 'c', null, 'd', 'e',  null, null,'f']

Right before rendering, you may use the filter operation you have as an example or simply filter out all falsy values by using .filter(Boolean) on the array, prior to rendering. This would look something like this:

...
<div>{menuItems.filter(Boolean).map((menuItem) => <p key={menuItem}>{menuItem}</p> )}</div>
...

Example 2:

What may be another issue you are having is in the event you have repeated items in your array along with null items. At what point you need to make sure each key is in fact unique. An easy and alternative way to go by this is to instead use the index, or a random number as your key instead of the actual value you have in the array:

const menuItems = ['a', 'a', 'b', 'b' 'c', null,'d','e', null, null,'f']
...
return <div>{menuItems.filter(Boolean).map((menuItem, index) => <p key={index}>{menuItem}</p> )}</div>

Example 3:

A third case that is relevant to talk about is if you have an array of objects, at which point you may need to filter by a particular property and the item itself. Consider the following menu items:

const menuItems = [
    null,
    { property: 'a' },
    { property: 'b' },
    { property: 'c' },
    {},
    null
]

You would now be required to check for the whole item being null of if the property itself is null (or falsy for that matter), so your filter will look more like this:

<div>{menuItems.filter((menuItem) => menuItem && menuItem.property)).map((menuItem) => <p key={menuItem.property}>{menuItem.property}</p> )}</div>

And of course, the same logic applies if you have repeated properties, you will need to find something unique instead of the actual property item to be the key. So for the sake of a simple example, use the index which will allow each item to be unique in this particular case:

<div>{menuItems.filter((menuItem) => menuItem && menuItem.property)).map((menuItem, index) => <p key={index}>{menuItem.property}</p> )}</div>

Important note:

In general, I would not recommend using any kind of label that may not be unique to be the key. Ideally you want it to be a value that you know will always be unique so that this problem isn't later created if somehow repeated items are added to the array.

Because of that, using the index as the key is a common practice or any more specific unique id property of an array of objects.

And finish that off, here is a demo illustrating each of the examples:

const App = () => {
  const menuItems1 = ['a', 'b', 'c', null, 'd', 'e',  null, null,'f']
  const menuItems2 = ['a', 'a', 'b', 'b', 'c', null,'d','e', null, null,'f']
  const menuItems3 = [
    null,
    { property: 'a' },
    { property: 'b' },
    { property: 'c' },
    {},
    null
]

  return (
  <div>
    <h1>Example 1</h1>
    
    <h4>Simple array, no repeated elements, using the the unique key to be whatever is being rendered</h4>
    <div>{menuItems1.filter(Boolean).map((menuItem) => <span key={menuItem}>{menuItem} &nbsp;&nbsp;&nbsp;</span> )}</div>
  
  <h1>Example 2</h1>
  <h4>Simple array, with repeated elements, using the the unique key to be the index</h4>
      <div>{menuItems2.filter(Boolean).map((menuItem, index) => <span key={index}>{menuItem} &nbsp;&nbsp;&nbsp;</span> )}</div>
      
 <h1>Example 3- A</h1>
   <h4>Array of objects, no repeated elements, using the rendered property to be the key</h4>
   <div>{menuItems3.filter((menuItem) => menuItem && menuItem.property).map((menuItem) => <span key={menuItem.property}>{menuItem.property} &nbsp;&nbsp;&nbsp;</span> )}</div>
   
   <h1>Example 3- B</h1>
   <h4>Array of objects, no repeated elements, using the rendered index to be the key</h4>
   
    <div>{menuItems3.filter((menuItem) => menuItem && menuItem.property).map((menuItem, index) => <span key={index}>{menuItem.property} &nbsp;&nbsp;&nbsp;</span> )}</div>


  
  </div>
  )
}


ReactDOM.render(
    <App />,
    document.getElementById('app')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="app"></div>
theJuls
  • 6,788
  • 14
  • 73
  • 160