score:30

Accepted answer

No. Default props are only shallowly merged.

However, one approach might be to have a Child component for each item. That way each Child component receives one object from the item array, and then the default props will be merged as you expect.

For example:

var Parent = React.createClass({

  propTypes: {
    heading: React.PropTypes.string,
    items: React.PropTypes.arrayOf(React.PropTypes.shape({
      href: React.PropTypes.string,
      label: React.PropTypes.string,
    })).isRequired
  },

  getDefaultProps: function() {
    return {
      heading: 'this works',
      items: [{
        href: '/',
        label: ' - this does not - ',
      }],
    };
  },

  render: function() {
    return (
      <div>
        {this.props.item.map(function(item) {
          return <Child {...item} />
        })}
      </div>
    );
  }

});

var Child = React.createClass({

  propTypes: {
    href: React.PropTypes.string,
    label: React.PropTypes.string
  },

  getDefaultProps: function() {
    return {
      href: '/',
      label: ' - this does not - '
    };
  },

  render: function() {
    return (
      <div />
        <p>href: {this.props.href}</p>
        <p>label: {this.props.label}
      </div>
    );
  }

});

score:0

You could use a getter instead of calling this.props. You'd have to have a lot of items for it to be an expensive method. You could also modify items as I did below and then set it in the state, but React suggests against deriving state from props.

class Foo extends React.Component {
  static propTypes = {
    heading: PropTypes.string,
    items: PropTypes.arrayOf(PropTypes.shape({
      href: PropTypes.string,
      label: PropTypes.string,
    })).isRequired
  }

  static defaultLabel = ' - this does not - '
  static defaultHref = '/'

  get items() {
    return this.props.items.map((item) => ({
      href: item.href || this.defaultHref,
      label: item.label || this.defaultLabel,
    }));
  }

  render() {
    return (
      <div>
        {this.items.map(({href, label}) => <a href={href}>{label}</a>)}
      </div>
    );
  }
}

Related Query

More Query from same tag