21

I'm currently inheriting an ES6 React base component in the following way:

model.js (base component):

class ModelComponent extends React.Component {

    render() {
        // Re-used rendering function (in our case, using react-three's ReactTHREE.Mesh)
        ...
    }

}

ModelComponent.propTypes = {
    // Re-used propTypes
    ...
};

export default ModelComponent;

Then I have two extending components that both look basically like this:

import ModelComponent from './model';

class RobotRetroComponent extends ModelComponent {

    constructor(props) {

        super(props);

        this.displayName = 'Retro Robot';

        // Load model here and set geometry & material
        ...

    }

}

export default RobotRetroComponent;

(Full source code here)

This appears to work fine. Both models are showing up and working as I would expect.

However, I have read in multiple places that inheritance is not the correct approach with React - instead I should be using composition. But then again, Mixins are not supported in React v0.13?

So, is the approach I'm taking above OK? If not, what's the problem, and how should I do this instead?

3
  • Mixins are supported in React v0.13, just not when using ES6 classes. You can still use the React.createClass({mixins:[]}) format to mixin functionality. Commented May 15, 2015 at 12:30
  • Thanks @Crob. Would that be better than using ES6 'class' inheritance then? The above feels simpler to me...? Commented May 15, 2015 at 12:51
  • If the only re-used part of your component is its render function and its propTypes, why note have your components compose it in their own render methods? In React, composition is preferred over inheritance. Commented May 15, 2015 at 14:06

1 Answer 1

36

The Facebook team recommends 'using idiomatic JavaScript concepts' when writing React code, and since there is no mixin support for ES6 classes, one should just use composition (since you are just making use of idiomatic Javascript functions).

In this case, you can have a composeModal function that takes a component and returns it wrapped in a higher-order, container component. This higher-order component will contain whatever logic, state, and props you want passed down to all of its children.

export default function composeModal(Component){

   class Modal extends React.Component {

       constructor(props){
           super(props)
           this.state = {/* inital state */}
       }

       render() {
           // here you can pass down whatever you want 'inherited' by the child
           return <Component {...this.props} {..this.state}/>
       }

   }

   Modal.propTypes = {
      // Re-used propTypes
      ...
   };

   return Modal
}

Then you can use the composition function like so:

import composeModal from './composeModal';

class RobotRetroComponent extends React.Component {

    constructor(props) {
        super(props);
        this.displayName = 'Retro Robot';
        // Load model here and set geometry & material
        ...
    }

    render(){
        return /* Your JSX here */
    }
}

export default composeModal(RobotRetroComponent);
Sign up to request clarification or add additional context in comments.

9 Comments

Thanks. I also want to re-use a constructor, for loading the models... I'm still wondering whether in some cases maybe it's best to just be pragmatic & use inheritance if it makes sense. After all, the mantra was only ever to "favour" composition over inheritance? (thoughtworks.com/insights/blog/…) I'm going to mark this as accepted though, because it's helped me think through it & I reckon it'll help me decide on a solution. For other viewers, you might like to change 'Modal' and 'ModelComponent' to 'Model' just to avoid confusion :)
I understand what you are saying, and on the face of it, it doesn't seem like inheritance would the be the wrong approach per se. However, the React team keeps re-iterating that the library is at heart a 'functional' library, so I suppose composition would be more aligned with this functional approach. Also we should keep in mind that the way of creating components using object-oriented patterns might be deprecated in the future in favor of a more functional style see github.com/reactjs/react-future
@poshaughnessy any chance you had a final demo any where? I'm after the exact solution you propose but I still find the above code confusing, possibly because the names/demo isn't clear. Any help would be fantastic!
@sidonaldson Sorry for the slow follow-up. Here's my code: github.com/poshaughnessy/react-three-demo. I just removed the inherited base component for now, since it's only got a little bit of duplicated code. I'm just taking another look at this now though, for my slides here: github.com/poshaughnessy/react-threejs-fullstack-2015 Currently each slide is inheriting from a 'base-slide' component. I think I'll try the way Jonathan suggested next...
Just because inheritance could be over used in OOP, and frowned upon among today's hyped technologies, it doesn't mean that it's bad. I'm very disappointed.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.