Course: Section

Get Started with Modern React: Step by Step

Episode: Title

S02・V21: Composition vs. Inheritance (Part 1)

Date Created: July 17th, 2019
Last Updated: 27 days ago

Objectives
  1. We will point out that it is recommended to use composition instead of inheritance in React.
  2. We will use the “children” prop to hold any elements between the opening and closing tag of the rendered component.
  3. We will learn that specialized components are created in React by composition, where a more generic component is configured with props.
Watch Video
Duration: 7m 25s

Containment

React has a powerful composition model, and we recommend using composition instead of inheritance to reuse code between components. In this video, we will consider a few problems where developers new to React often reach for inheritance, and show how we can solve them with composition.

Some components don’t know their children ahead of time. This is especially common for components like a Sidebar or a Dialog that represent generic “boxes”. We recommend that such components use the special children prop to pass children elements directly into their output.

To show an example, let’s start off importing React and ReactDOM. We will also import the index.css file, because we will be adding some CSS styling. Ultimately, we want to render a custom React element called WelcomeDialog to the DOM.

src/index.js
import React from "react";
import ReactDOM from "react-dom";

import "./index.css";

ReactDOM.render(
  <WelcomeDialog />,
  document.getElementById("root")
);

Now, let’s define the WelcomeDialog component.

We will have it return a div. As children to the div, we will show an h1 header element, with a className of Dialog-title, and a p element, with a className of Dialog-message. We will add the class styles later.

Now, let’s say we wanted to put a thick colored border around the h1 and p elements. We could do that by adding a class with some CSS to the encompassing div that holds them as children.

On the other hand, if we wanted to create thick colored borders around other elements as well, it would be better to create a reusable component that could apply this styling to any elements. Let’s call this component FancyBorder. We will add in in place of the encompassing div. Then, we will create a prop called color, and pass the string value of blue to it.

src/index.js
const WelcomeDialog = () => {
  return (
    <FancyBorder color="blue">
      <h1 className="Dialog-title">Welcome</h1>
      <p className="Dialog-message">
        Thank you for visiting our spacecraft!
      </p>
    </FancyBorder>
  );
};

Now, we will define the FancyBorder component.

It will return a div with a className whose value is determined by the color prop. Any elements between the opening and closing tag of the rendered FancyBorder component are automatically passed via props in a variable called children. Since FancyBorder renders {props.children} inside a div, the passed elements appear in the final output.

src/index.js
import React from "react";
import ReactDOM from "react-dom";

import "./index.css";

const FancyBorder = props => {  return (    <div className={`FancyBorder FancyBorder-${props.color}`}>      {props.children}    </div>  );};
const WelcomeDialog = () => {
  return (
    <FancyBorder color="blue">
      <h1 className="Dialog-title">Welcome</h1>
      <p className="Dialog-message">
        Thank you for visiting our spacecraft!
      </p>
    </FancyBorder>
  );
};

ReactDOM.render(
  <WelcomeDialog />,
  document.getElementById("root")
);

Save the file, and observe that the h1 and p render on the page.

Add Styles

Now, let’s go to index.css and add the CSS styles.

First, let’s add styles for the class Dialog-title. Make the margin zero. And, the font-family of sans-serif. Next, we will increase the font-size for the class Dialog-message. The FancyBorder class adds some padding and a solid, thick border. Finally, the FancyBorder-blue class sets the border-color to blue.

src/index.css
.Dialog-title {
  margin: 0;
  font-family: sans-serif;
}

.Dialog-message {
  font-size: larger;
}

.FancyBorder {
  padding: 10px;
  border: 10px solid;
}

.FancyBorder-blue {
  border-color: blue;
}

Specialization / Composition

We will now turn to talking about “specialization” in the context of React. Sometimes we think about components as being “special cases” of other components. For example, we might say that a WelcomeDialog is a special case of a Dialog. In React, this is also achieved by composition, where a more “specific” component renders a more “generic” one and configures it with props.

Let’s go back to index.js. We will create a more generic Dialog component. We will move the return expression of WelcomeDialog into the Dialog component. And now we will make it more generic by making the title and message texts be provided via props. In WelcomeDialog, we will return the Dialog element, passing in values for the props title and message.

src/index.js
import React from "react";
import ReactDOM from "react-dom";

import "./index.css";

const FancyBorder = props => {
  return (
    <div className={`FancyBorder FancyBorder-${props.color}`}>
      {props.children}
    </div>
  );
};

const Dialog = props => {  return (    <FancyBorder color="blue">      <h1 className="Dialog-title">{props.title}</h1>      <p className="Dialog-message">{props.message}</p>    </FancyBorder>  );};
const WelcomeDialog = props => {
  return (
    <Dialog      title="Welcome"      message="Thank you for visiting our spacecraft!"    />  );
};

ReactDOM.render(
  <WelcomeDialog />,
  document.getElementById("root")
);

Save the file and observe that the same title and message render to the page.

Summary

We pointed out that it is recommended to use composition instead of inheritance in React. We used the “children” prop to hold any elements between the opening and closing tag of the rendered component. And, we learned that specialized components are created in React by composition, where a more generic component is configured with props.

Next Up…

In the next video, we will continue discussing composition versus inheritance.