0

I'm trying to build a nav menu that gets its data (links, and link names) from an array called navMenuItems. navMenuItems has an array within it for child links as I'm trying to build a menu similar to the mobile https://www.w3schools.com/ one. I'm running into the error "Each child in a list should have a unique "key" prop.", I'm not sure where I should be adding the key prop to, but I have a feeling its this section (full code below):

                    <div>
                      {item.childMenuItems.map((childItem) => {
                        <Link
                          key={childItem.name.replace(' ', '')}
                          href={childItem.url}
                        >
                          {childItem.name}
                        </Link>;
                      })}
                    </div>

Array:

const navMenuItems = [
    { name: 'Home', url: '#' },
    {
      name: 'Skincare Goal',
      url: '#',
      childMenuItems: [
        { name: 'Anti-Aging', url: '/categories/anti-aging' },
        { name: 'Wound Healing', url: '/categories/wound-healing' },
        { name: 'Acne-Fightning', url: '/categories/acne-fightning' },
        { name: 'Brightening', url: '/categories/brightening' },
        { name: 'UV Protection', url: '/categories/uv-protection' },
      ],
    },
    {
      name: 'Ingredients',
      url: '#',
      childMenuItems: [
        { name: 'AHA (All Types', url: '/ingredients/aha' },
        { name: 'Anti-Aging', url: '/ingredients/bha' },
        { name: 'BHA (Salicylic Acid)', url: '/ingredients/anti-aging' },
        { name: 'PHA (All Types)', url: '/ingredients/pha' },
        { name: 'Niacinamide', url: '/ingredients/niacinamide' },
        { name: 'Vitamin A', url: '/ingredients/vitamin-a' },
        { name: 'Hyaluronic Acid', url: '/ingredients/hyaluronic-acid' },
        { name: 'Ceramides', url: '/ingredients/ceramides' },
        { name: 'Azelaic Acid', url: '/ingredients/azelaic-acid' },
      ],
    },

NavBar code snippet:

<ul>
            {navMenuItems.map((item) => {
              /* Implement child links, check if parent link has childen, if not, use link tag, else use a or button? */
              if (
                !Array.isArray(item.childMenuItems) ||
                !item.childMenuItems.length
              ) {
                return (
                  <li key={item.name.replace(' ', '')}>
                    <Link href={item.url}>{item.name}</Link>
                  </li>
                );
              } else {
                return (
                  <>
                    <li key={item.name.replace(' ', '')}>
                      <Link href={item.url}>{item.name}</Link>
                    </li>
                    <div>
                      {item.childMenuItems.map((childItem) => {
                        <Link
                          key={childItem.name.replace(' ', '')}
                          href={childItem.url}
                        >
                          {childItem.name}
                        </Link>;
                      })}
                    </div>
                  </>
                );
              }
            })}
          </ul>
  • Welcome to Stack Overflow! You gave a lot of great detail here. A future search for "Fragment" will help find answers like [this question](https://stackoverflow.com/questions/59390955/can-i-add-a-key-prop-to-a-react-fragment) for problems with this React feature in the future. Good luck and thanks for joining! – Robert P Jul 22 '22 at 23:54
  • Kind of off-topic, but `name.replace(' ', '')` seems weird. Just use `name` directly. – xehpuk Jul 23 '22 at 00:03
  • That's fair @xehpuk, I'll change that. – Bungee Gum Jul 23 '22 at 02:33

1 Answers1

0

Your problem is this part, here:

          } else {
            return (
              <>
                {/* ... everything else ... */}
              </>

The <> is actually a react element called a Fragment. Most of the time <> is sufficient. The fragment is the element that needs the key for the first map, not the inner li element. When a key is in a fragment, the full name must be used. So instead, do:

          else {
            return (
              <React.Fragment key={item.name.replace(' ', '')}>
                {/* ... everything else ... */}
              </React.Fragment>
Robert P
  • 15,707
  • 10
  • 68
  • 112
  • Also see: https://stackoverflow.com/questions/59390955/can-i-add-a-key-prop-to-a-react-fragment – Robert P Jul 22 '22 at 23:54
  • 1
    Ah, thank you, Robert. So the part I wasn't getting seems to be whatever the parent container is that you're returning must be passed a key attribute. – Bungee Gum Jul 22 '22 at 23:57