DEV Community

Cover image for Containment, Specialization and Inheritance in React-Native/React
Shivam Gupta
Shivam Gupta

Posted on

Containment, Specialization and Inheritance in React-Native/React

In this blog, I’m going to talk about Containment, Specialization and Inheritance in React-Native/React, the difference between them and how you can use them to reuse your code.

First, while the examples shown below are related to react-native, the theory is also applicable to react. The concepts might help you to go DRY. Let’s discuss these points one by one.

Containment

When you wrap your component(s) within a higher-order component, it’s a containment. Some components don’t know their children ahead of time. Some common cases are Sidebar, Dialog. And for the sake of reusability, some components better be generic.

The following problem can make this clear:

Problem Statement:

We have a table of n rows and two columns. The columns can hold not just the text but any other JSX component (Button, Image, Icon) too. However, it’s is known that it’s going to be a text for 80% of the time.

Solution:

React containment model can be useful in these cases.
The idea is to create a wrapper — GenericRow that can hold any JSX component. Furthermore, we can create a CustomRow for Text component only. This is also called Specialization. Yes, I know that I’ve been talking a lot, so let me write the code for you:

/* Generic Row that doesn’t know about its children */

const GenericRow = (props) => (
 <View {...props}>
   /* Left column or Left child */
   <View style={styles.column}>{props.left}</View>

   /* Right column or Right child */    
   <View style={styles.column}>{props.right}</View>
 </View>
);

/**
 * Specialization of our Generic Row
 * This component is going to be used when it’s known that left and right are texts
 **/
const CustomRow = ({ left, right, ...props }) => (
 <Generic
   { ...props }
   /* Left child */
   left = { <Text>{left?.toString()}</Text> }
   /* Right Child */
   right = { <Text>{right?.toString()}</Text> }
 />
);

/* Child of CustomRow | First Row */
const NameRow = (props) => (
 <CustomRow left="Developer’s Name" right="Shivam Gupta" />
);

/* Second Row for the age */
const AgeRow = (props) => <CustomRow left="Age" right="22" />;

/* Action: Connect | Third row */
const ConnectActionRow = (props) => (
  /* Notice Generic Row not a CustomRow! */
 <GenericRow left = { <Text>Connect</Text> } right = {<Button title="Hit me!" />} />
);

Enter fullscreen mode Exit fullscreen mode

Here, CustomRow is a specialization of the GenericRow which is going to be used frequently as per the problem statement. Notice that the ConnectActionRow component is contained by the GenericRow and not by the CustomRow, unlike the NameRow and AgeRow.

Just using concepts of containment, we have the code which is easier to read, debug and maintain.

Now let’s talk about specialization.

Specialization:

Sometimes a component is a special case of the other component. For example, Error Text (traditionally, bold and red) is a special case of Text.

The following problem will help you understand this better.

Problem Statement:

You’re creating a medium-sized non-trivial react-native application that is going to have 20 screens. You require to prompt the danger text (for validation error) on at least 7 to 8 screens.

Solution:

You’ll create a separate component for it. Of course! Any sane developer would do that. If that’s the case you already know about Specialization. For beginners, let me just write a code:

const Error = ({ children, fontFamily, style }) => (
 /* User may overwrite the color, or fontWeight using his own style. */
    <Text 
      style={[
         { color: red, fontWeight: "bold" }, 
         /* Notice this written after the our style, letting user to overwrite color and fontWeight. */
         { ...style}
      ]}
    >{children}</Text>
);
Enter fullscreen mode Exit fullscreen mode

Again, the idea for this implementation is to use the DRY principle and at the same time allow the user of this component to overwrite our default stying whenever the developer wants.

Inheritance

React neither prefers nor does provide anything much for inheritance. Most of the time, you’re not going to need it. Whatever you could do using inheritance, you can achieve the same using Containment or Specialization. The following is the statement from the react’s official documentation:

“At Facebook, we use React in thousands of components, and we haven’t found any use cases where we would recommend creating component inheritance hierarchies.”

Difference between Containment, Specialization and Inheritance

While Containment, Speicializtion and Inheritance may sound similar but they are very different. The following may help you understand it.

  1. The table CONTAINS/HAS rows. Neither table is a specialization of rows, nor it’s an inheritance.
  2. Pulsar IS a Bike. Neither this is an example of containment nor specialization.
  3. Welcome Dialog is a special case of Dialog. Neither this is an example of containment nor inheritance.

The difference between containment and inheritance is of IS/HAS relationship.

Conclusion

The main objective of the containment and specialization concept is to follow the DRY (Don’t Repeat Yourself) principle. Because redundant code is hard to maintain, harder to debug and using these concepts will make your code maintainable and less error-prone.

Discussion (0)