Dirk J. Faber
Dirk J. Faber

Reputation: 4701

Why must I use the spread operator in this JSX element?

I have a functional component that returns an anchor element that can have the attributes href and role, depending on the props that are passed to it:

function Item(props) {
    return (
        <a {...props.toSubMenu && {role: 'button'}} {...props.href && {href: props.href}}>
            {props.children}
        </a>
    );
}

While creating this component, I first tried to pass props without using the spread operator like so: <a {props.toSubMenu && {role: 'button'}}>, but this gave me the error:

Parsing error: Unexpected token, expected "..."

So at the moment, I have my component working the way I want it, but I cannot figure out why I must use the spread operator. In other parts of my code (like on line 4) I do not need it. I have read about it in this question and this one and in the react documentation, but I am still uncertain.

Upvotes: 0

Views: 242

Answers (3)

Athish Murugan
Athish Murugan

Reputation: 331

In JSX, the {} do not output strings as is the case in many templating languages, you need to look at it as an assignment where the left hand is the property, Now to set the value depending on the setting prop just follow the same logic: to explain why the error says expected "...". If the {} do not fall on the right side of an assignment it is expected that you want to spread multiple properties, SO,try this

function Item(props) {
    return (
        <a role={props.toSubMenu ? 'button' : undefined} href={props.href}>
            {props.children}
        </a>
    );
}

Upvotes: 0

ZenG
ZenG

Reputation: 169

  • I extract this from your code as an example
function Item(props) {
    return (
        <a {...props.toSubMenu && {role: 'button'}} >
            {props.children}
        </a>
    );
}
  • Let's assume props.toSubMenu is not null
  • after conversion to pure html: (this doesn't work at all!)
function Item(props) {
    return (
        <a {role: 'button'} >
            {props.children}
        </a>
    );
}
  • if you use spread operator like this
function Item(props) {
    return (
        <a {...props.toSubMenu && ...{role: 'button'}} >
            {props.children}
        </a>
    );
}
  • it will spread out the object {role: 'button'} as:
function Item(props) {
    return (
        <a role="button" >
            {props.children}
        </a>
    );
}
  • one thing to note: in
{...props.toSubMenu && {role: 'button'}}

the outermost {} is not a symbol for object, it's a sign for code snippet to run in jsx file.

Conclution

  • you don't have to use spread operation, this also works
function Item(props) {
    return (
        <a role={props.toSubMenu && 'button'} >
            {props.children}
        </a>
    );
}
  • but since role is already defined in props, why not just spread it out?

Upvotes: 0

BerndS
BerndS

Reputation: 409

I assume you want to give <a/> the role buttonin case toSubMenu is true? And that you just want to forward href? In that case, would the following work?

function Item(props) {
    return (
        <a role={props.toSubMenu ? 'button' : undefined} href={props.href}>
            {props.children}
        </a>
    );
}

Upvotes: 1

Related Questions