Post Header Image
Christian Kozalla • 8th of Jul '20 • 8 min.

Defining the Goals of Changing the Banner Component

As I was recently building a Banner component with a nice, dynamically changing colorful background, to which I added a Typewriter component to have an animation of text typed into the headline, I was only making it work for the main page of DevDiary. Yesterday, I wanted to use the Banner on a different page with different text input. Calling an instance of the <Welcome /> component, which already includes the <Typewriter />, on a different page only gave me the same text as I already had on the main page, i.e. "Welcome to DevDiary" etc. I didn't want that text on that page.

I had to make the component reusable, and I definitely knew how! But first, let's look at the (non-reusable) status-quo:

My deepest component <Typewriter /> looked like this:

// inside Typewriter class component
componentDidMount() {
  const Typer = new Typewriter("type", this.props.content);
  Typer.type; // make Typewrite type
};

In <Welcome /> I was calling a <Typewriter /> instance like this:

<div className="banner">
  <Typewriter content={['Hi, I am Christian', 'Welcome to DevDiary']} />
</div>

Calling <Welcome /> in another component was done like this:

<Welcome />

So I was using props to pass content from <Welcome /> to <Typewriter />, but on a level too shallow. To choose content, where <Welcome /> was inserted I had to make sure <Welcome /> was accepting props in the fist place.

My journey began on the top-most level: The <Welcome /> component.

import React, { useEffect } from "react";
import Typewriter from "./Typewriter";

const Welcome = (props) => {
  // color-gradient logic here, called from useEffect
    return (
    <div id="welcome">
      <div className="banner">
        <Typewriter
          content={props.text}
          rounds={props.rounds}
          padding={props.padding ? props.padding : "2.5rem"}
          center={props.center}
        />
      </div>
      <style jsx>{`
        .banner {
          display: flex;
          justify-content: ${props.center ? "center" : "flex-start"};
          align-items: center;
          height: 150px;
          width: 100%;
          padding: 0 3rem;
        }
      `}</style>
    </div>
}

<Welcome /> is expecting props text, rounds, padding and center. text is a required input, otherwise the <Typewriter /> won't type anything. But I included default values for rounds, padding and center in case no values are defined when calling the instance.

Now, inserting is done like this:

<Welcome
  text={['Hi, I am Fred', 'Welcome to London']}
  rounds={3}
  padding="3rem"
  center={false}
/>

rounds determines how often the text will be typed back and forth. padding sets the left padding to have the text bound left, but still being centered. center centers the text making in move on both ends, know what I mean?! If center is true, padding will be set to 0, automatically.

Let's take a look how <Typewriter /> is receiving and processing those props.

class Typewriter extends React.Component {
  constructor(id, arr, rounds = 1) {
    super(id, arr, rounds);
    if (process.browser) {
      this.el = document.getElementById(id);
      this.blinker = document.getElementById('blinker');
      this.period = 150;
      this.interval = '';
      this.deleteInterval = '';
      this.word = '';
      this.add = true;
      this.textArray = arr;
      this.roundtrip = 0;
      this.rounds = rounds;
    }
  }

  // Typewriter methods defined here

  componentDidMount() {
    // content sets the contents which Typewriter types as an Array
    // rounds sets how often the Typewriter types the contents; last item stays visible
    // padding sets left padding in order to center text; props Type is String e.g. "4rem"
    let Typer = new Typewriter('type', this.props.content, this.props.rounds);
    Typer.type();
  }

  render() {
    return (
      <div className="flex-text">
        <h1 id="type"></h1>
        <h1 id="blinker">|</h1>
        <style jsx>{`
          h1 {
            font-family: 'Dancing Script', 'Norican', 'Roboto';
            font-size: 3em;
            margin: 0;
            padding: 0;
          }

          .flex-text {
            display: flex;
            flex-flow: row wrap;
            padding-left: ${this.props.center ? '0' : this.props.padding};
          }

          #type {
            display: inline-block;
            text-shadow: 2px 2px #ddd;
          }

          .blink {
            visibility: hidden;
          }

          @media (max-width: 500px) {
            h1 {
              font-size: 2em;
            }
          }
        `}</style>
      </div>
    );
  }
}

padding-left value is based on a ternary operator checking this.props.center and setting "0" or this.props.padding.

Thanks for reading through my post on how to make this <Welcome /> component reusable. Have a nice day! ..and keep coding =)

Banner