Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Random data in defaultProps

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.

like image 689
Radosław Miernik Avatar asked Feb 06 '23 18:02

Radosław Miernik


1 Answers

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.

like image 144
quw Avatar answered Feb 09 '23 07:02

quw