8
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

styled-componentsでReactコンポーネントを継承したスタイル拡張

Posted at

概要

タイトルの通り、styled-componentsを使ってReactコンポーネント(styledされていないものも含む)を継承してスタイルを拡張させる方法のメモです。

通常のstyled-componentを継承したスタイル拡張

まず、別のstyled-componentのスタイルを継承した新しいコンポーネントを作成する方法を見ていきます。

方法

継承させたいもとのコンポーネント名をstyled()コンストラクタ内に書くだけ。

テンプレートリテラル``内に拡張したいスタイルを書くと、追記したスタイルが継承もとのコンポーネントのスタイルに拡張されます。

👇公式のDEMOが分かりやすいのでどうぞ
https://styled-components.com/docs/basics#extending-styles

(本題)Reactコンポーネントを継承したスタイル拡張

では、普通のReactのコンポーネント(styledされていないものも含む)を継承したいときはどうでしょう?

方法

この場合は、継承させたいもとのコンポーネントにpropsとしてclassNameを渡す必要があります。

👇検証DEMO
https://codesandbox.io/s/sweet-brattain-9be06u?file=/src/App.tsx

こちらのDEMOで試してみてもらうと分かりますが、
ButtonBlue.tsxから className の記述を削除すると、ButtonRedコンポーネントは赤ではなく青いままになります。

公式ドキュメント

styled-components、Emotionそれぞれの公式ドキュメントにもそのようなことが書かれています。

styled-components

The styled method works perfectly on all of your own or any third-party component, as long as they attach the passed className prop to a DOM element.

Emotion

styled can style any component as long as it accepts a className prop.

(余談)コンポーネント呼び出し時のclassNameの指定を回避したい(TypeScriptを使用している場合)

classNameを渡せばよいのは分かったものの、コンポーネントを呼び出す際に毎度classNameを指定するのはなんか嫌だなぁ...という時の回避方法を考えました。
(わたしの場合は指定していないと「classNameがない!」と怒られました)

※おことわり※
ここで紹介するのは苦肉の策?のような感じなので、もっと良い方法あれば是非教えていただきたいです!

classNameをオプショナルプロパティとする

コンポーネントに渡すpropsの型定義をする際に、classNameはオプショナルプロパティとして定義してあげます。

ButtonBlue.tsx
type ButtonProps = {
  children: ReactNode;
  className?: string;  // オプショナルプロパティとして定義
};

export const ButtonBlue: React.VFC<ButtonProps> = ({ children, className }) => {
  return (
    <Button className={className}>
      <a href="https://relic.co.jp">{children}</a>
    </Button>
  );
};

これで、コンポーネントを呼び出す際は特にclassNameを渡さなくても怒られずに済みます。

App.tsx
import { ButtonBlue } from "./ButtonBlue";
import { ButtonRed } from "./ButtonRed";

export default function App() {
  return (
    <div className="App">
      <ButtonBlue>ボタン1</ButtonBlue>
      <ButtonRed>ボタン2</ButtonRed>
    </div>
  );
}

参考

8
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?