four-eyes
four-eyes

Reputation: 12385

How to use prop spreading and extracting props at the same time

I have two components like this

const TextLarge = (props) => { // props are classes,color and children
    return <Text
               classes={'text-large-style'}
               {...props}>
               {props.children}
           </Text>
}

const Text = ({
    children,
    color,
    classes,
}) => {
    return <p
               className={clsx('text-styles', classes)}
               style={{color: color}}>
               {children}
           </p>
}

Now, when I pass a class to <TextLarge />

<TextLarge
    classes='some-special-style'>
    Foo
<TextLarge>

This overwrites classes='text-large-style' because {...props} spreads classes='some-special-style into <TextLarge/> after classes='text-large-style.

Is there a (React/elegant) way to take classes out of props, so something like

const TextLarge = (props) => { // props are classes,color and children
    return <Text
               classes={clsx('text-large-style', props.classes)}
               {...props}> // no classes in here
               {props.children}
           </Text>
}

yet still spreading the rest of the {...props} into <Text />? I know that could change the order, making classes={clsx('text-large-style', props.classes)} overwrite {...props}

const TextLarge = (props) => { // props are classes,color and children
    return <Text
               {...props}
               classes={clsx('text-large-style', props.classes)}>
               {props.children}
           </Text>
}

but I want more control.

Upvotes: 1

Views: 48

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1073978

Is there a (React/elegant) way to take classes out of props

Yes, you can use destructuring with a rest target:

const TextLarge = ({classes, ...rest}) => {
    // ...
};

Actually, you probably want to remove children as well:

const TextLarge = ({classes, children, ...rest}) => {
    // ...
};

Then ...rest won't include classes (or children), and you can include classes in your explicit prop (if you want to pass them on):

const TextLarge = ({classes, children, ...rest}) => {
    return (
        <Text {...rest} classes={`text-large-style ${classes ?? ""}`}>
            {children}
        </Text>
    );
};

Upvotes: 1

Related Questions