ReactSmallTips: Liskov Substitution in React components
At some point in your career as a software developer you might start worrying about not just writing code that works, but code that is readable, easy to understand, easy to maintain and scalable. In other words, a good quality code.
In order to achieve that, there are some guidelines like: patterns, paradigms and principles. Those guidelines were designed by real developers to solve well known real problems in programming. Among them, we have SOLID Principles.
SOLID is an acronym for the first five object-oriented design (OOD) principles by Robert C. Martin (aka Uncle Bob).
I’ve already written 2 articles covering the Open-closed Principle and the Interface Segregation Principle in React. In this one we’re going to see the Liskov Substitution Principle applied in React Components.
So, what Liskov Substitution Principle (LSP from now on) is all about? The oficial definition goes like..
If for each object o1 of type S there is an object o2 of type T such that for all prgrams P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T
Clean Architecture — Robert C. Martin
I don’t know about you, but, for me that definition wasn’t easy to get at first glance. So, after reading some other paraphrased definitions, I got the idea. Bring that concept to the React world, we could say that:
A subComponent based on a baseComponent could substitute the baseComponent without changing the application’s behavior.
I know it is still not very clear, so let’s jump into an example that I hope will make the concept of LSP cristal clear for you.
Let’s say in your application a lot of componentes are styled using flex box and its properties. In order to avoid repetition— defing display: flex, flex-direction, justify-content, etc..— and to make it easier to use flex box styles in our components, let’s create a component called, unsurprisingly, FlexBox.
To create such styled component, I’m going to use a lib called @emotion/react to helps us styling components with CSS in JS
So, first we create our FlexStyled
Note: a flex box can have more than those properties. But, to keep the example as simple as possible, I’m going to use just some of them
Now we can use that FlexStyled to create our FlexBox component
And then, we can use our Flexbox in our application
As a result, we got the default behavior of flex box
flexDirection: ‘row’, justifyContent: ‘flex-start’ and alignItems: ‘stretch”
The purple border shows the limits of the FlexBox.
A common use of flex box is to perfectly center children both horizontally and vertically, and the following code snippet can be repeated a lot in your application
Result
To avoid that annoying repetition everytime we want to center things with flex box, let’s create a sub-type of our FlexBox, the FlexCenter
As you can see, the sub-type component — FlexCenter — can be created just by extending props from FlexBox and returning the FlexBox component itself, passing the value “center” for both align and justify props
Now we can go to our App, and substitute the FlexBox for FlexCenter. Wait a minute, can we substitute a baseComponent for a sub-type of that component and still get the same result (behavior)?
If we can, isn’t that the LSP after all? Let’s see..
And we still got the expected behavior
To summarize, in order to make it easier to style components with flex box and avoid annoying repetition, we created a FlexBox component with handy props. Then we created a sub-type of that component, the FlexCenter. As we saw in the LSP concept, we should be able to substitute the a baseComponent for a subComponent of that one, and still get the expected behavior.
Since the relationship between sub-types and base-types is basically an extension, the Liskov Substitution Principle is very close to the Open Closed Principle. You should check that out!
So that was the LSP (Liskov Substitution Principle) in action with React components. Hope this post was helpful.
You can find the code on my Github.
Thanks a lot for reading this far.