So I was going over the Inheritance vs Composition discussion all over the place. I will talk about my use case.
I am creating a hierarchy of components using react. Stuff like button -> buttonBar for example. So for these sort of things, whatever functionalities I have defined in the button component needs to be present as is in the buttonBar components.
class Button extends React.Component {
shouldComponentUpdate() {
//do some prevalidation
return result;
}
myButtonfn = () => {
//do Something here
}
myButtonfn2 = () => {
//doSomething else
}
}
class ButtonBar extends Button {
shouldComponentUpdate() {
return myLogic && super.shouldComponentUpdate.call(this);
}
myButtonBarfn = () => {
//I should be able to do this
this.myButtonfn();
this.myButtonfn2();
}
}
Currently I have implemented inheritance to achieve this. What is the correct way of going about this? I don't want to go back to es5 way of using with this. React.createClass.
I believe this page (and specifically this section) should answer your question.
No, you shouldn’t use inheritance for this.
Normally you would just create a more “generic” component that accepts functions as props (if you need its behavior to be customizable), and a more “specific” component that renders (not inherits) that “generic” component and passes its methods as props, e.g.
class MyCustomButton extends React.Component {
handleSomething() {
}
render() {
return <Button onSomething={this.handleSomething} />;
}
}
It’s hard to say more because your example is a bit vague but this should give you the idea.
@gaearon , what do you propose when I've got something like this:
class Button extends React.Component {
getButtonStyle() {
return {backgroundColor: "blue"}
}
render() {
return <button style={this.getButtonStyle()}>{this.props.children}</button>
}
}
class SuccessButton extends Button {
getButtonStyle(){
return {backgroundColor: "green"}
}
}
class DangerButton extends Button {
getButtonStyle(){
return {backgroundColor: "red"}
}
}
isn't this a little more easy to test (only test for getButtonStyle for example) and less code? I know I can accept style as a prop, this is just an example, is this bad? why is it bad?
Say I've got a Collection component which allows only CollectionItems as it's child.
class Collection extends React.Component {
render() {
// this.checkForValidity
}
}
Now say I want to create a slightly different type of Collection, I can just overwrite checkForValidity and whatever is required, however if I was using composition, I'd have to go to collection and either add a list of allowed child (not really good since Collection doesn't want SpecialCollectionItem), or accept allowedChild as a prop.
Thoughts?
@cyberhck We went the inheritance route for some components for a large project at work. But this only worked great for really simple components and even then the benefit of composition via props or functions was much easier to test in our case. During the curse of the project (1 year in) we regretted the decision to rely to much on inheritance greatly and have moved to a more composable model (similar to what @gaearon explains).
Inheritance, although being part of the language itself and easier for humans to grok, only works great when the relation between the parent and the child is basically set in stone and won't change much. Composition on the other hand is awesome when the relationship between objects is changing quite often. Think of different ui requirements or adapting to new designs, which always require components with similar functionality, but slightly different behaviours attached to them.
Quite a lot has been discussed on this topic through various issues on different frameworks and github repos. I'd highly recommend trying out both approaches and see what is easiest for you. At least for our team, after having tried the inheritance approach, composition made so much more sense and simplified at lot of things for us.
Now say I want to create a slightly different type of Collection, I can just overwrite checkForValidity and whatever is required, however if I was using composition, I'd have to go to collection and either add a list of allowed child (not really good since Collection doesn't want SpecialCollectionItem), or accept allowedChild as a prop.
Anything you want to “override”, just make it a prop. <Collection checkForValidity={this.checkForValidity} />. We use this approach at Facebook with great success for all “base” components.
Most helpful comment
@cyberhck We went the inheritance route for some components for a large project at work. But this only worked great for really simple components and even then the benefit of composition via props or functions was much easier to test in our case. During the curse of the project (1 year in) we regretted the decision to rely to much on inheritance greatly and have moved to a more composable model (similar to what @gaearon explains).
Inheritance, although being part of the language itself and easier for humans to grok, only works great when the relation between the parent and the child is basically set in stone and won't change much. Composition on the other hand is awesome when the relationship between objects is changing quite often. Think of different ui requirements or adapting to new designs, which always require components with similar functionality, but slightly different behaviours attached to them.
Quite a lot has been discussed on this topic through various issues on different frameworks and github repos. I'd highly recommend trying out both approaches and see what is easiest for you. At least for our team, after having tried the inheritance approach, composition made so much more sense and simplified at lot of things for us.