I'm using React for quite a long time and I've encountered an interesting problem: basically, I want to use defaultProps as fallbackProps - that's what they are for, but there's one difficulty - both defaultProps property from stateless / class extend Component API and cached getDefaultProps() from React.createClass API are immutable (and constant).
Example:
var ExampleComponent = React.createClass({
    getDefaultProps: function () {
        return {
            number: Math.random()
        };
    }
    // ...
});
// or equivalent with ES6 classes
class ExampleComponent extends React.Component {
    // ...
}
ExampleComponent.defaultProps = {
    number: Math.random()
};
// then...
<main>
    <ExampleComponent />            // cached random
    <ExampleComponent />            // cached random
    <ExampleComponent number={1} /> // 1
    <ExampleComponent />            // cached random
    <ExampleComponent />            // cached random
</main>
The problem is, that I want dynamic defaultProps - separate for each component instance.
Example:
<main>
    <ExampleComponent />            // fresh random
    <ExampleComponent />            // fresh random
    <ExampleComponent number={1} /> // 1
    <ExampleComponent />            // fresh random
    <ExampleComponent />            // fresh random
</main>
I know, it's easy to achieve that behavior with state (getInitialState is per-component), but I'm wondering if it is possible with no state and no HOC or similar approach.
Yes. This is possible by using ES5 getters to define the defaultProps object:
ExampleComponent.defaultProps = Object.create({}, {
  number: {
    enumerable: true,
    get: () => Math.random()
  }
});
Demo
As you noticed, defaultProps is a static member, and as such is only initialized once per class. However, when React.createElement is called, it creates a new copy of defaultProps by enumerating through all of the properties and copying them to a new, blank object (this enumeration is why enumerable: true had to be set in the descriptor). Relevant part of React's source:
  // Resolve default props
  if (type && type.defaultProps) {
    var defaultProps = type.defaultProps;
    for (propName in defaultProps) {
      if (props[propName] === undefined) {
        props[propName] = defaultProps[propName];
      }
    }
  }
defaultProps[propName] invokes the getter, which causes a new random number to be generated, which is then stored in props.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With