概要
タイトルの通り、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それぞれの公式ドキュメントにもそのようなことが書かれています。
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.
styled
can style any component as long as it accepts aclassName
prop.
(余談)コンポーネント呼び出し時のclassNameの指定を回避したい(TypeScriptを使用している場合)
classNameを渡せばよいのは分かったものの、コンポーネントを呼び出す際に毎度classNameを指定するのはなんか嫌だなぁ...という時の回避方法を考えました。
(わたしの場合は指定していないと「classNameがない!」と怒られました)
※おことわり※
ここで紹介するのは苦肉の策?のような感じなので、もっと良い方法あれば是非教えていただきたいです!
classNameをオプショナルプロパティとする
コンポーネントに渡すpropsの型定義をする際に、classNameはオプショナルプロパティとして定義してあげます。
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を渡さなくても怒られずに済みます。
import { ButtonBlue } from "./ButtonBlue";
import { ButtonRed } from "./ButtonRed";
export default function App() {
return (
<div className="App">
<ButtonBlue>ボタン1</ButtonBlue>
<ButtonRed>ボタン2</ButtonRed>
</div>
);
}