2
votes

I appreciate it if anybody can explain why the following code works.

I created a NumberListBase React component. Then created another one, named NumberList and derived it from NumberListBase.

In the constructor of the two components I purposely don't pass 'props' argument to the parent class when calling super().

class NumberListBase extends React.Component {
  constructor(props) {
    super();
    Log("NumberListBase.ctor: ", this.props, props);
  }
}
class NumberList extends NumberListBase {
  constructor(props) {
    super();
    Log("NumberList.ctor: ", this.props, props);
  }
  render() {
    const numbers = this.props.numbers;
    const listItems =
          numbers.map((n) => <li key={`${n}`}>{n}</li>);
    return (<ul>{listItems}</ul>);
  }
}

const numbers = [1, 2, 3, 4, 5];

ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

I expected that render() will fail, because this.props would be undefined in it.

The log messages I put in the constructors shows clearly that the 'props' argument and 'this.props' are 'undefined' in NumberListBase constructors.

But, in complete amazement, the component rendered correctly and showed the numbers, meaning that the 'props' got to React.Component somehow and React.Component could put it inside 'this.props'!

This is a codepen I created for this question.

https://codepen.io/mansoor-omrani/pen/oKaMXV

I also created a jsfiddle snippet to test how constructors work in a class hierarchy.

https://jsfiddle.net/omrani/thnj2zu4/11/

I checked React.Component source code to see how this class is defined.

https://github.com/facebook/react/blob/master/packages/react/src/ReactBaseClasses.js

function Component(props, context, updater) {
  this.props = props;
  this.context = context;
  // If a component has string refs, we will assign a different object later.
  this.refs = emptyObject;
  // We initialize the default updater but the real one gets injected by the
  // renderer.
  this.updater = updater || ReactNoopUpdateQueue;
}

React.Component is just a simple function. I'm still wondering how, where and when 'this.props' was set!

1

1 Answers

2
votes

When you call super() without the props, you’ll still be able to access this.props in the render and other methods because React assigns props on the instance right after calling your constructor.

We pass props into the super method only when we need to use props inside the constructor.

The reason why they implemented this behaviour is unclear, probably for future compatibility reasons, as Robin Pokorny replied to the below question.

ref: What's the difference between "super()" and "super(props)" in React when using es6 classes?