What do these three dots do in my React component?
Let's talk about the spread operator in JavaScript. These little dots (...) may look weird, but they're really helpful for managing props and state.
export function Button(props) {
return <button {...props}>{props.children}</button>;
}
The spread operator is used to expand/pluck out an iterable object into individual pieces. It looks just like rest parameters but does the opposite - it 'spreads' an array or object into its single elements while rest parameters packs them in.
So, the example above is getting the props object passed in the Button function/component, and spreading that props object's individual key/value pairs into the button element, while explicitly passing the props.children property into that button to be displayed as text.
With that said, these two pieces of code would achieve the same effect:
<Button onClick={handleOnClick} className="danger" disabled={isDisabled} type="submit">Close</Button>
const buttonProps = {
onClick: handleOnClick,
className: 'danger',
disabled: isDisabled,
type: 'submit',
};
<Button {...buttonProps}>Close</Button>
What's going on in the second example is we're getting the object and spreading the individual key/value pairs into individual pieces. There isn't anything magical about it, it's just vanilla JavaScript.
Spreading into an element can be really helpful when you're working with components that have a ton of props, for example:
<Button
onClick={handleOnClick}
className="danger"
disabled={isDisabled}
type="submit">
Close
</Button>
This can get out of hand quickly. So, using the spread syntax for the button element here can make your code cleaner and easier to read.
Rest parameters share very similar syntax to the spread operator - those three dots look the same but have quite the opposite purpose.
export function Button({ children, ...props }) { // rest parameters
return <button {...props}>{children}</button>; // spreading props into the button
}
In this example, we're using rest parameters to pluck out the children property from the object and assigning the 'rest' of the properties to the props object. This is useful when you want to pass down the children prop to the button element and keep the rest of the props in a separate object.
The way I personally tell the difference between rest and spread is by looking at where the three dots are placed. If they're in the function parameter, they're rest parameters (we're gathering the 'rest' of the arguments into one). If they're in the element, it's the spread operator (we're spreading the object out).
So, the code above is equivalent to this silly example:
export function Button({ children, ...props}) {
return (
<button onClick={props.handleOnClick} className={props.className} disabled={props.isDisabled} type={props.type}>
{children}
</button>
);
}
Key Points
- The spread operator is used to expand/pluck-out an iterable into individual pieces.
- Rest parameters are used to gather the 'rest' of the arguments of a function into one - or in this case, React props - object.
- The spread operator is used in the element, while rest parameters are used in function parameters.