Ahrengot Ahrengot - 5 months ago 19
Javascript Question

Extending React.js components

One of the things I appreciate the most about Backbone.js is how simple and elegant inheritance works. I'm starting to get to grips with React, and can't really find anything in react that resembles this Backbone code

var Vehicle = Backbone.View.extend({
methodA: function() { // ... }
methodB: function() { // ... }
methodC: function() { // ... }
});

var Airplane = Vehicle.extend({
methodC: function() {
// Overwrite methodC from super
}
});


In react we have mixins, and using those we could get somewhat close to the above example if we went like this

var vehicleMethods = {
methodA: function() { // ... }
methodB: function() { // ... }
}

var Vehicle = React.createClass({
mixins: [vehicleMethods]
methodC: function() {
// Define method C for vehicle
}
});

var Airplane = React.createClass({
mixins: [vehicleMethods]
methodC: function() {
// Define method C again for airplane
}
});


This is less repetitive than defining the same stuff over and over again, but it doesn't seem to be nearly as flexible as the Backbone way. For instance, I get an error if I try to redefine/overwrite a method that exists in one of my mixins. On top of that, the React.js way is more code for me to write.

There is some incredibly clever stuff in react, and it feels like this is more the case of me not getting how to properly do this, than it feels like a feature missing from React.

Any pointers are greatly appreciated.

Answer

To get something that resembles inheritance (actually composition as pointed out in comments), you can make an Airplane in your example wrap itself in a Vehicle. If you want to expose methods on Vehicle in the Airplane component, you can use a ref and connect them one-by-one. This is not exactly inheritance (it's actually composition), particularly because the this.refs.vehicle will not be accessible until after the component has been mounted.

var Vehicle = React.createClass({
    ...
});

var Airplane = React.createClass({
    methodA: function() {
      if (this.refs != null) return this.refs.vehicle.methodA();
    },
    ...
    render: function() {
        return (
            <Vehicle ref="vehicle">
                <h1>J/K I'm an airplane</h1>
            </Vehicle>
        );
    }
});
Comments