Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Selectively rendering optional component properties in React JSX

Tags:

reactjs

I have a use case where I have an Image component that has a required "src" attribute and an optional "link" attribute which looks like this:

var Image = React.createClass({

propTypes: {
  link: React.PropTypes.string,
  event: React.PropTypes.object,
  src: React.PropTypes.string.isRequired
},

handleClick: function(event, link) {
   analytics.track(event)
    .then(function() {
      window.location = link;
    });
},

render: function() {
  return (
    <img className='image' src={this.props.src} onClick={this.handleClick.bind(this, this.props.event, this.props.link)} />
  );
} });

If I want to selectively include optional props when I call the Image component, how would I do that elegantly? My initial idea was to do a ternary expression like this, except this is not valid JSX:

render: function() {
    return (
        <Image src={this.props.src} {this.props.link.hasOwnProperty('value') ? link=this.props.link.value : ''} />
    )
}

In the example above "this.props.link" is an object that may or may not contain a property called "value" which includes the hyperlink to browse to when the Image is clicked. Also, rather than simply supplying an empty string as the value for the "link" prop, I would prefer to simply leave it out altogether if there is no link.value present.

My reasoning for this is so that on the Image component I can add the css "img:hover {cursor: pointer;}" only if the img actually links somewhere, as opposed to setting it globally which violates UX rules for my app.

I know that I can simply render the "link" prop inside a ternary where it includes the value of the link if it exists and is an empty string if it doesn't, but for curiousity's sake I wanted to see if there maybe was another way to accomplish this.

I also would like to avoid having to do a bunch of conditional statements that create a lot of redundant JSX code like this:

render: function() {
    if (this.props.link.hasOwnProperty('value')) {
        return <Image link={this.props.link.value} src={this.props.src.value} />;
    } else {
        return <Image src={this.props.src.value} />;
    }
    .... // other optional properties
}

Imagine how out of hand that would get if you have a lot of optional props that you want to leave off...

like image 786
eriklharper Avatar asked Nov 05 '14 23:11

eriklharper


1 Answers

You seem to be overthinking it.

<Image src={this.props.src} link={this.props.link.value} />

In your components you should usually treat any falsy value as omitted.

if (this.props.link) {
   ...
}

An exception would be for numbers, or the rare (and best avoided case) where it's a boolean defaulting to true.


A more direct answer would be to use spread (new in 0.12).

var props = {src: this.props.src};
if (this.props.link.hasOwnProperty('value')) {
  props.link = this.props.link.value;
}

<Image {...props} />

or

var extraProps = {};
if (this.props.link.hasOwnProperty('value')) {
  extraProps.link = this.props.link.value;
}

<Image src={this.props.src} {...extraProps} />
like image 138
Brigand Avatar answered Oct 15 '22 00:10

Brigand