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