53

I have:

const section = cloneElement(this.props.children, {
  className: this.props.styles.section,
  ...this.props,
});

Inside this.props, I have a styles property that I don't want to pass to the cloned element.

How can I do?

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Fez Vrasta
  • 14,110
  • 21
  • 98
  • 160

4 Answers4

74

You can use the object rest/spread syntax:

// We destructure our "this.props" creating a 'styles' variable and
// using the object rest syntax we put the rest of the properties available
// from "this.props" into a variable called 'otherProps' 
const { styles, ...otherProps } = this.props;
const section = cloneElement(this.props.children, {
  className: styles.section,
  // We spread our props, which excludes the 'styles'
  ...otherProps,
});

I assume that you already have support from this syntax based on your code above, but please be aware that this is a proposed syntax which is made available to you via the babel stage 1 preset. If you get syntax errors on execution you can install the preset as follows:

 npm install babel-preset-stage-1 --save-dev

And then add it to the presets section of your babel configuration. For example in your .babelrc file:

 "presets": [ "es2015", "react", "stage-1" ]

Update based on comment on question by OP.

Okay, so you say that you already have a styles variable declared before this block? We can manage this case too. You can rename your destructured arguments to avoid this.

For example:

const styles = { foo: 'bar' };

const { styles: otherStyles, ...otherProps } = this.props;
const section = cloneElement(this.props.children, {
  className: otherStyles.section,
  // We spread our props, which excludes the 'styles'
  ...otherProps,
});
ctrlplusb
  • 12,847
  • 6
  • 55
  • 57
  • 1
    I don't think this works out of the box with the react preset. It would be useful if you explained how to configure Babel to make use of this. – Felix Kling Jun 15 '16 at 15:15
  • This is a really creative answer, I didn't know this was possible with the spread operator – Michael Parker Jun 15 '16 at 19:34
  • You could also destructure directly into className like this: `const { styles: { section: className }, ...otherProps } = this.props;`. – BamaPookie Nov 10 '22 at 13:21
29

You could use Object Rest Spread operator magic.

const props = { a: 1, b: 2, c: 3 };
const { a, ...propsNoA } = props;
console.log(propsNoA); // => { b: 2, c: 3 }

So in your case it would be:

const { styles, ...propsNoStyles } = this.props;
const section = cloneElement(this.props.children, {
  className: this.props.styles.section
  ...this.propsNoStyles,
});
am0wa
  • 7,724
  • 3
  • 38
  • 33
2

or you can do something like this...

var newProp = (this.props = {p1, p2,...list out all props except styles});
alex
  • 479,566
  • 201
  • 878
  • 984
user796870
  • 81
  • 2
  • 8
1

I like ctrlplusb's answer, but here is an alternative using Object.assign if you don't want to add a new babel preset:

const section = cloneElement(this.props.children, {
    className: this.props.styles.section,
    ...Object.assign({}, this.props, {
        styles: undefined
    })
});
Michael Parker
  • 12,724
  • 5
  • 37
  • 58
  • 4
    Then you have an undefined property – Fez Vrasta Jun 15 '16 at 20:17
  • 1
    That shouldn't make a difference for your application. If you try to access a `prop` that was not passed to your component, the value would be `undefined` anyways. This is almost equivalent, provided you don't rely on the existence of a particular key supplied to your props. – Michael Parker Jun 15 '16 at 21:13