Open/Closed principle on React.js
Tags: react
Published: 2020-07-24 21:51:34

Imagine that you have the following requirement:

*Create a Component in React.JS that displays properties from a Car, e.g. number of wheels, number of doors, if it's electric or has gas, etc.*


So you start creating your component like this:


``` react
function Car() {
    return (
        <div>
            <h1>4 wheels</h1>
            <h1>5 doors</h1>
            <h1>electric</h1>
        </div>
    )
}
```

Simple right? But wait! There is a new requirement. We need to show the same properties for another vehicle -> a bicycle!

So now... what do we do? We can add a bunch of ifs!

``` react
function Vehicle(props) {
    return (
        <div>
            {
               props.type === 'car' ? 
               <h1>4 wheels</h1> : 
               <h1>2 wheels</h1>
            }
            {
               props.type === 'car' &&
               <h1>5 doors</h1>
            }
            {
               props.type === 'car' ?
               <h1>electric</h1> :
               <h1>powered by humans!</h1>
            }
        </div>
    )
}
```

I'm sure you already guessed that this can become a mess if we add a new type of vehicle.

This happens because this component is not following the Open/Closed principle. Why?

## Open/Closed principle

The traditional definition is "software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification".
And this exact definition can be applied to Components!

So here comes a new iteration (not the last one):
What if we create a component for every type of vehicle?

Let's see:

``` react
function Car() {
    return (
        <div className='vehicle'>
            <h1>4 wheels</h1>
            <h1>5 doors</h1>
            <h1>electric</h1>
        </div>
    )
}
```

``` react
function Bycicle() {
    return (
        <div className='vehicle'>
            <h1>2 wheels</h1>
            <h1>powered by humans!</h1>
        </div>
    )
}
```

``` react
function Plane() {
    return (
        <div className='vehicle' >
            <h1>3 wheels</h1>
            <h1>A lot of doors</h1>
            <h1>Gas</h1>
        </div>
    )
}
```

And then the only thing we need to do is map every component to its type:

``` javascript
const vehicleComponents = {
    'car': () => { return <Car> },
    'bicycle': () => { return <Bicycle> },
    'plane': () => { return <Plane> },
}
```

But wait!

There is a possibility that someone is saying:
**Those components are looking disturbingly the same**
You are right! That can be generalized!

Basically we have to identify what's similar on the three components.

1. They all share the same class
2. They all display properties in H1s

So we create a new component that can receive this properties as props!

``` react

interface VehicleProps {
    wheels: string
    doors: string | undefined // bicycle does not have doors!
    fuel: string
}

function Vehicle(props: VehicleProps) {
    return (
        <div className='vehicle' >
            <h1>props.wheels</h1>
            {props.doors && <h1>props.doors</h1>}
            <h1>props.fuel</h1>
        </div>
    )
}
```

Now we have our generic component. Let's use it!

``` react
function Car() {
    return (
        <Vehicle 
           wheels='4 wheels' 
           doors='5 doors' 
           fuel='electric'
        >
    )
}
```

``` react
function Bycicle() {
    return (
        <Vehicle 
           wheels='2 wheels'
           fuel='human'
        >
    )
}
```

``` react
function Plane() {
    return (
        <Vehicle 
           wheels='3 wheels'
           doors='a lot'
           fuel='gas'
        >
    )
}
```

So now we have our refactored and generic components ready to be used and maintained!

So let's say now we have a new type of vehicle. The only thing we have to do is create the component that reuses the Vehicle component, add the new component to the vehicleComponents and you are done!

``` javascript
const vehicleComponents = {
    'car': () => { return <Car> },
    'bicycle': () => { return <Bicycle> },
    'plane': () => { return <Plane> },
    'new-vehicle': () => { return <NewVehicle> },
}
```

Now let's say you want to change the styles of how the vehicles display. You only have to modify the styles in one place -> the Vehicle component.

And that is the magic and beauty of the Open/Closed principle :)

Less IFs, more smiles

![Real devs don't use if](https://i.ytimg.com/vi/rnud1EjmHBM/hqdefault.jpg)