Home > Blockchain >  How to lay out dynamic children in NavLink v6
How to lay out dynamic children in NavLink v6

Time:06-03

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

CodePudding user response:

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>

Alternatively you could move the link text value out of the children function since it doesn't appear to depend on active link status.

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>

CodePudding user response:

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