Rolf Rolf - 1 month ago 13
React JSX Question

Why is "normal" ES5 prototypal inheritance not supported in React?

I am under the impression that ES6 classes are basically a syntactic sugar around the ES5 objects system.
As I am trying to run React without a transpiler, I figured that I could use just use the old syntax for defining object "classes" that "inherit" from React.Component.

var Board = function(props, state) {
var instance = {};

instance.props = props;
instance.context = state;

return(instance);
};

Board.prototype = Object.create(React.Component.prototype);

Board.prototype.render = function() {
return(
// ...stuff
)
};


But that does not work!

react.js:20478 Warning: Board(...): No `render` method found on the returned component instance: you may have forgotten to define `render`
react.js:6690 Uncaught TypeError: inst.render is not a function(…)


I found alternatives in this gist, and the following works:

var Board = function(props, state) {
var instance = Object.create(React.Component.prototype);

instance.props = props;
instance.context = state;

instance.prototype.render = function() {
return(
// ...stuff
)
};

return(instance);
};


I have also found out that I can use the
React.createClass
helper.

But I still would like to understand why React would not handle classes defined in such a common way. It seems to me that ES6 classes are instanciated before being used. I see no reason why ES5-style classes would not be instanciated as well, with similar results.

Answer

Why is “normal” ES5 prototypal inheritance not supported in React?

It is, although using React.createClass is probably your better option. It's just that the code in your question isn't doing the standard ES5 class-like inheritance tasks. In particular:

  • You're returning an instance of a plain object, not an instance of Board, and so Board.prototype isn't used by the object. Normally, a constructor function shouldn't return anything, and should use the object new created when calling it, which it receives as this.
  • You're not giving React.Component its chance to initialize the instance.
  • You're not setting constructor on Board.prototype (although I don't know whether React cares; a lot of things don't).

It works if you set it up in the normal way. Here's an ES5 example without React.createClass, see comments:

// The component
function Foo(props) {
    // Note the chained superclass call
    React.Component.call(this, props);
}

// Set up the prototype
Foo.prototype = Object.create(React.Component.prototype);
Foo.prototype.constructor = Foo; // Note

// Add a render method
Foo.prototype.render = function() {
    return React.createElement("div", null, this.props.text);
};

// Use it
ReactDOM.render(
    React.createElement(Foo, {
        text: "Hi there, the date/time is " + new Date()
    }),
    document.getElementById("react")
);
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>