How to lay out dynamic children in NavLink v6

Viewed 166

In NavLink I am trying to pass the isActive prop in a function as the children, and also have the name of my link be dynamic.

I'm getting multiple errors and I'm not sure what I'm doing wrong (I am new to React).

import { NavLink } from 'react-router-dom';

const navigation = [
  { name: 'Home', href: '/', icon: HomeIcon, current: true },
  { name: 'Users', href: '/Users', icon: UsersIcon, current: false }
]

function classNames(...classes: string[]) {
  return classes.filter(Boolean).join(' ')
}

export class Nav extends Component<any, any> {
  
  constructor(props: boolean) {
    super(props);
  }
  
  render() {
    return (
      <>
        <nav className="mt-5 flex-1 px-2 space-y-1">
          {navigation.map((item) => (
            <NavLink
              key={item.name}
              to={item.href}
            >
              {({ isActive }) => (
                <item.icon
                  className={classNames(
                    isActive ? 'text-gray-300' : 'text-gray-400 group-hover:text-gray-300',
                    'mr-3 flex-shrink-0 h-6 w-6'
                  )}
                  aria-hidden="true"
                />
                {item.name}
              )}
            </NavLink>
          ))}
        </nav>
      </>
    );
  }
}

On the NavLink component I get:

This JSX tag's 'children' prop expects a single child of type 'ReactNode | ((props: { isActive: boolean; }) => ReactNode)', but multiple children were provided.

On the item.name line I get:

Parsing error: ')' expected.

And on the last closing curly brace before the closing NavLink I get:

Unexpected token. Did you mean {'}'} or &rbrace;?

2 Answers

React components should return a single node element. Wrap the returned JSX in a React.Fragment component.

Example:

<NavLink
  key={item.name}
  to={item.href}
>
  {({ isActive }) => (
    <>
      <item.icon
        className={classNames(
          isActive
            ? 'text-gray-300'
            : 'text-gray-400 group-hover:text-gray-300',
          'mr-3 flex-shrink-0 h-6 w-6'
        )}
        aria-hidden="true"
      />
      {item.name}
    </>
  )}
</NavLink>

This JSX tag's 'children' prop expects a single child of type 'ReactNode | ((props: { isActive: boolean; }) => ReactNode)', but multiple children were provided.

wrap item.icon and item.name in React.Fragment as you can't return multiple children from a function. eg:-

<>
<item.icon className={classNames(isActive ? 'text-gray-300' : 'text-gray-400 group-hover:text-gray-300','mr-3 flex-shrink-0 h-6 w-6')} aria-hidden="true" />
                      {item.name}</>
Related