People like me who come from the typical Object Oriented background coming from PHP, Java, C# etc would say yes, code inheritance is a good practice. But what do you do when you are working with a language which does not follow your typical OO paradigms?! Yes, I’m talking about Javascript – the language people like to love and hate at the same time. And on top of that, you happen to be working with React, it becomes an altogether different matter.
Javascript does not have the same code inheritance concept as something like PHP or Java etc. Sure, ES6 introduced classes in Javascript and while that did make writing code for someone like me easier, if you look at it, its just syntactical sugar. Almost all modern browsers support ES6 at present and for that matter even ES7, ES8 & ES9. Yet, we use Babel to transpile the code back to JS basics away from the neat & clean looking syntactical sugar.
Basic rule to indulge in code inheritance is to be able to reuse code and keep things clean and better organised. So we can do this:
class Vehicle {
protected string $_type = '';
protected string $_maker = '';
protected string $_model = '';
protected string $_colour = '';
protected bool $_is_amphibious = false;
public function __construct() {}
public function get_type() : string {
return $this->_type;
}
public function get_maker() : string {
return $this->_maker;
}
public function get_model() : string {
return $this->_model;
}
public function get_colour() : string {
return $this->_colour;
}
public function is_amphibious() : bool {
return $this->_is_amphibious;
}
}
class Car extends Vehicle {
protected string $_type = 'car';
protected bool $_is_amphibious = false;
public function __construct( string $maker, string $model, string $colour ) {
$this->_maker = $maker;
$this->_model = $model;
$this->_colour = $colour;
}
}
$lambo = new Car(
'Lamborghini',
'Huracan Evo Spyder',
'Verde Selvans'
);
printf(
'The car is %s from %s in %s colour and it looks fabulous.',
$lambo->get_model(),
$lambo->get_maker(),
$lambo->get_colour(),
);
It looks right here however different languages have their own take of code reusability. For instance, since this is PHP code, I might instead go with this version of it:
trait Vehicle {
protected string $_type = '';
protected string $_maker = '';
protected string $_model = '';
protected string $_colour = '';
protected bool $_is_amphibious = false;
public function get_type() : string {
return $this->_type;
}
public function get_maker() : string {
return $this->_maker;
}
public function get_model() : string {
return $this->_model;
}
public function get_colour() : string {
return $this->_colour;
}
public function is_amphibious() : bool {
return $this->_is_amphibious;
}
}
class Car {
use Vehicle;
public function __construct( string $maker, string $model, string $colour ) {
$this->_type = 'car';
$this->_is_amphibious = false;
$this->_maker = $maker;
$this->_model = $model;
$this->_colour = $colour;
}
}
$lambo = new Car(
'Lamborghini',
'Huracan Evo Spyder',
'Verde Selvans'
);
printf(
'The car is %s from %s in %s colour and it looks fabulous.',
$lambo->get_model(),
$lambo->get_maker(),
$lambo->get_colour(),
);
It would get me the same result but more importantly, the Car
would be free to inherit another class. Class inheritance in PHP is a very expensive commodity in the sense that there can only be a single parent.
Now coming back to Javascript & React – class inheritance is available ES6 onwards in a similar way, as far as syntax is concerned. But when you’re making React components, do you really need it?!
Last night while I was working on refactoring some code on a pet project, I was sort of in a bind. ( I’m new to React at the moment. ) I had this JSX for displaying messages and I wanted to make it more re-usable and have cleaner implementation. So I started out with creating a base MessageDisplay
component and my first thought was, should I extend this to specific components to display specific messages based on the context! And then I realised I don’t need to actually do that. And so this is what I ended up doing:
import React from 'react';
export default class MessageDisplay extends React.Component {
constructor( props ) {
super( props );
this.setVars();
}
setVars = () => {
this.type = this.props.type;
};
render() {
if ( ! React.isValidElement( this.props.messageJsx ) ) {
return null;
}
return (
<div className={`message ${this.type}`}>
{this.props.messageJsx}
</div>
);
}
}
import React from 'react';
import MessageDisplay from './MessageDisplay';
export default class SuccessMessageDisplay extends React.Component {
constructor( props ) {
super( props );
this.setVars();
}
setVars = () => {
this.type = 'success';
this.messageJsx = this.props.messageJsx;
};
render() {
return (
<MessageDisplay
type={this.type}
messageJsx={this.messageJsx}
/>
);
}
}
Now to display a success message, all I had to do was this:
import React from 'react';
import SuccessMessageDisplay from './SuccessMessageDisplay';
export default class MyComponent extends React.Component {
constructor( props ) {
super( props );
}
getMessageJsx = () => {
return (
<>
<div className="header">Congrats!</div>
<div className="content">
This is a success message displaying on
your screen successfully!
</div>
</>
);
};
render() {
return (
<>
<div className="top box">
<SuccessMessageDisplay
messageJsx={this.getMessageJsx()}
/>
</div>
<div className="content box">
Some content and UI to be displayed here.
</div>
</>
);
}
}
And then the light in my brain turned on and told me to refer to React docs and see if there is any suggestion there on this topic. Turns out there is a React doc on Composition vs Inheritance! It explains it quite well with code examples on why inheritance is actually not needed in React components.
Sure, in above example I could’ve extended MessageDisplay
in SuccessMessageDisplay
and worked with that and that would have worked ( like this ). But there is no good reason to do it. Just because we can do something does not mean it should be done. Keeping both MessageDisplay
and SuccessMessageDisplay
as separate components works just as well, allows for code-reuse and keeps the code neat and organised.
Its something similar to the PHP Traits – they are about code reusability without implementing the parent-child relationship between classes and I’m glad that the Traits were added in PHP instead of class inheritance being updated to allow for multiple parents. Having something like Traits opened up other possibilities and gives a lot of flexibility in how you arrange and manage your code while keeping the basic principle of code reusability in effect. Same way React’s Composition allows for more flexibility in the code and encourages code reusability without having to resort to funky code in components trying to make them work with inheritance.