DEV Community

Cover image for ReactJS SOLID Principle ~OCP (Open Closed Principle)~
Ogasawara Kakeru
Ogasawara Kakeru

Posted on

ReactJS SOLID Principle ~OCP (Open Closed Principle)~

The OCP principle states that:
The extent of the component or function should be open, and its modification should be closed.

Bad code

import React, { VFC } from "react";

type Props = {
  title: string;
  type: "default" | "withLinkButton" | "withNormalButton";
  href?: string;
  buttonText?: string;
  onClick?: () => void;
};

export const Title: VFC<Props> = ({
  title,
  type,
  href,
  buttonText,
  onClick,
}) => {
  return (
    <div style={{ display: "flex", justifyContent: "space-between" }}>
      <h1>{title}</h1>
      {type === "withLinkButton" && (
        <button onClick={onClick}>
          <a href={href}>{buttonText}</a>
        </button>
      )}
      {type === "withNormalButton" && (
        <button onClick={onClick}>{buttonText}</button>
      )}
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

This component receives props such as title, type, and so forth.
There are three use cases: a non-displaying button; a displaying button to the left of the title, and a normal displaying button.

*Why does this component breach the OCP? *

Let's consider a scenario.
After the product was released, a manager ordered us to create a page with a tooltip that appears next to the title.

Therefore, I modified the page that displays the tooltip, adding the withTooltip type to the props type.

Each time we expand the functionality, we have to modify the component. This means that, when you modify the component, you have to check for any degradation. This slows down the development process.

Although there are a variety of solutions, the Composition Component Pattern is used in this case.

import { VFC, FC } from "react";

type TitleProps = {
  title: string;
};

export const Title: FC<TitleProps> = ({ title, children }) => {
  return (
    <div style={{ display: "flex", justifyContent: "space-between" }}>
      <h1>{title}</h1>
      {children}
    </div>
  );
};

type TitleWithLinkProps = {
  title: string;
  href: string;
  buttonText: string;
};

export const TitleWithLink: VFC<TitleWithLinkProps> = ({
  title,
  href,
  buttonText,
}) => {
  return (
    <Title title={title}>
      <button>
        <a href={href}>{buttonText}</a>
      </button>
    </Title>
  );
};

type TitleWithButtonProps = {
  title: string;
  buttonText: string;
  onClick: () => void;
};

export const TitleWithButtonProps: VFC<TitleWithButtonProps> = ({
  title,
  buttonText,
  onClick,
}) => {
  return (
    <Title title={title}>
      <button onClick={onClick}>{buttonText}</button>
    </Title>
  );
};
Enter fullscreen mode Exit fullscreen mode

I broke the component down into smaller parts so that I could pass the inner component as a child. By doing this, if you need to implement the “additional modification to place a tooltip next to the title” mentioned earlier, for example, you simply need to draw the component that displays the tooltip within the TitleWithTooltip component. This will not affect the TitleWithButton or TitleWithLink components in any way.

Top comments (0)