68

Say I have 3 props that my class based component requires and implements i.e.

<Component propOne={this.props.one} propTwo={this.props.two}>
  {this.props.children}
</Component>

how would I pass down any other props that I originally don't expect, but say someone else using my component would want to use?

I was thinking

<Component propOne={this.props.one} propTwo={this.props.two} {...this.props} >
  {this.props.children}
</Component>

But am concerned about prop duplication

Ilja
  • 44,142
  • 92
  • 275
  • 498

5 Answers5

121

Use spread syntax:

const {propOne, propTwo, ...leftOver} = this.props;
// `leftOver` contains everything except `propOne` and `propTwo`

So your example would become:

const { propOne, propTwo, children, ...props } = this.props;

<Component propOne={propOne} propTwo={propTwo} {...props}>
    {children}
</Component>

Spread syntax (...) allows an iterable such as an array expression or string to be expanded in places where zero or more arguments (for function calls) or elements (for array literals) are expected, or an object expression to be expanded in places where zero or more key-value pairs (for object literals) are expected.

Source: MDN

Aryan Beezadhur
  • 4,503
  • 4
  • 21
  • 42
Kousha
  • 32,871
  • 51
  • 172
  • 296
  • 2
    This could be an option to keep it even shorter – brunettdan Nov 10 '19 at 13:42
  • if you want to override props it might have to be in the opposite order... –  Feb 28 '20 at 21:40
  • How can I type check this in TS? Currently, I have to list all props I use upfront, like this `interface MyCompProps { a: number, b: string }`, which is really cumbersome. – Minh Nghĩa Nov 02 '20 at 10:30
  • 2
    It might be a little late but you can type the rest props like this ```javascript interface MyCompProps { a: number; b: string;} const MyComp: React.FC> = (props) => { const { a, b, ...rest } = props; } ``` – Mert Simsek May 16 '21 at 18:38
6

The spread operator is great, but I was surprised I hadn't discovered it in the tutorials, and then it took forever to track down a reliable source describing it. In case you were doubting how it works, here are the details in the official ReactJS POD, from a little article called JSX In Depth...

If you already have props as an object, and you want to pass it in JSX, you can use ... as a “spread” operator to pass the whole props object. These two components are equivalent:

 return <Greeting firstName="Ben" lastName="Hector" />;
}

function App2() {
 const props = {firstName: 'Ben', lastName: 'Hector'};
 return <Greeting {...props} />;
}```

And, of course, for your case, where you want to pass only some of the children...

const Button = props => {
 const { kind, ...other } = props;
 const className = kind === "primary" ? "PrimaryButton" : "SecondaryButton";
 return <button className={className} {...other} />;
};

In the example above, the kind prop is safely consumed and is not passed on to the element in the DOM. All other props are passed via the ...other object making this component really flexible. You can see that it passes an onClick and children props.

Source: ReactJS.org: JSX In Depth, Specifying the React Element Type, Spread Attributes.

For your specific case...

const {propOne, propTwo, ...newChildProps} = this.props;
<Component
    propOne={this.props.one}
    propTwo={this.props.two}
    {...newChildProps}
>{children}</Component>
HoldOffHunger
  • 18,769
  • 10
  • 104
  • 133
2

✅ Here is how I do it:

export default function Button(props) {
  const { children, label, ...rest } = props;
  
  return (
    <button
      {...rest}
      aria-label={label}
    >
      {children}
    </button>
  )
}

✨ Just be aware sometimes you do not need attributes named the same as the given prop, so here I extracted label and passed it to aria-label.

Amir2mi
  • 896
  • 9
  • 13
0

Filter them?

function without(props, keys) {
  return Object.keys(props)
    .filter((key) => keys.indexOf(key) !== -1)
    .reduce((retVal, key) => {
      retVal[key] = props[key];
    }, {});
}

<Component propOne={this.props.one} propTwo={this.props.two} {...without(this.props, ['one', 'two'])} >
  {this.props.children}
</Component>
Maciej Chałapuk
  • 454
  • 3
  • 11
0

try to send whole properties as an Object under one property name. just like this

class ParentComponent extends Component{

    state={
      person:{
         id=1,
         name="rashid",
         family="behnam"
             }
         }
render(){
return <ChildComponent wholething={this.state.person} />
        }
}
//------------------------------------------
class ChildComponent extends Component{
render(){
     const {id,name,family}=this.props.wholething;
         return (
                <div someId={id}>
                   <h3>My name is :{name}</h3>
                   <h4>My family is :{family}</h4>
                </div>
                );
      }
}