styled-componentsをTypescriptで使う上でのTips
はじめに
今回はTypescript + Reactでstyled-componentsを使う場合のTipsを紹介します。
styleプロパティで直接記載するよりもスタイルの管理がしやすい+使い回しやすいといったメリットがあるのでおすすめです。
※普段はReact Nativeを扱っていますが、styled-componentsに着目した場合の使用感はほぼ同じといっていいので、サンプルコードはReactのものになります。
そもそもstyled-componentsとは
styled-componentsは所謂CSS in JSライブラリの一種になります。
名前が表す通り、JSもしくはTSのコード中にCSSを記載していく形になります。
デフォルトのReactプロジェクトだと、コンポーネント自体はJSやTSで記載しますが、スタイルはCSSファイルのまとまっています。
それらを 1ファイルにまとめる ことができるのが最大のメリットです。
スタイルはテンプレートリテラルで記載することを基本とし、作成したコンポーネントのスタイルを継承したり、さらに拡張したりすることができます。
上記の内容だけではピンとこない方も多いと思うので、実際に使ってみましょう。
実際に使ってみる
以下、実際に動くサンプルを作ってみる例です。
React + Typescriptのプロジェクトは既に作成してあるものとします。
インストール
yarn add styled-components
yarn add --dev @types/styled-components
基本的な書き方
以下にstyled-componentsを使って、ラベルの色を赤く、文字を太くした場合のボタンコンポーネントの例を示します。
import React from "react";
import styled from "styled-components";
// 基本的なstyled-componentsの使い方
const CustomButton = styled.button`
color: red;
font-weight: bold;
`;
このCustomButtonの使い方は、通常のbuttonコンポーネントと同じです。
<CustomButton>ほげほげ</CustomButton>
これはbuttonコンポーネントに下記のようにstyleを指定したのと同じになります。
<button style={{color: "red", fontWeight: "bold"}}>ほげほげ</button>
見てわかる通り、よりCSSに近い記法になっているかと思います。
このスタイルを指定している箇所は 「テンプレートリテラル」 と呼ばれています。
対して、上記の<button>の例のようなスタイルの指定の記法を 「オブジェクトリテラル」 と呼びます。
styled-componentsを使用することで、デフォルトのコンポーネントをそのままrenderするケースが減少するかと思います。
独自定義したコンポーネントにも対応している
では、自作のコンポーネントやライブラリからimportしてきたコンポーネントにもstyled-componentsでスタイルを適用したい場合はどうでしょうか。
styled-componentsではそういったコンポーネントもサポートしています。
以下に例を示します。
Hogeという<p>をラップしたシンプルなコンポーネントがあったとします。
import React from 'react';
const Hoge: React.VFC = (props) => <p {...props}>Original Component</p>;
このHogeに対してstyled-componentsでスタイルを指定したい場合は下記のように記載します。
import React from "react";
import styled from "styled-components";
const Hoge: React.VFC = (props) => <p {...props}>Original Component</p>;
// Hogeに対してスタイルを適用する
const CustomHoge = styled(Hoge)`
color: purple;
`
外部のライブラリからimportしてきたコンポーネントも同様に扱う事ができます。
プロパティによって変動するスタイルの定義
buttonコンポーネントでよくあるのが「disabledだけスタイルを変更したい」といったケースです。
styled-componentsでは、コンポーネントに渡されるプロパティの値によってスタイルを制御することも可能です。
その場合は以下のように記載します。
import React from "react";
import styled from "styled-components";
// props.disabledでcolorを変化させる
const CustomButton = styled.button`
color: ${(props: React.ButtonHTMLAttributes<HTMLButtonElement>) => props.disabled? 'red': 'blue' };
font-weight: bold;
`;
これでbuttonがdisabledの状態の時のみ文字色が赤くなり、それ以外の時は青くなります。
ここで使用しているpropsはbuttonのpropsの型と同じになります。
従って、propsはReact.ButtonHTMLAttributes<HTMLButtonElement>型となります。
プロパティをカスタムする
上記のbuttonのdisabledのようなプロパティではなく、独自で定義したプロパティを使いたい場合があるかと思います。
その場合はジェネリクスとして型を渡すことで対応することができます。
下記のように記載します。
import React from "react";
import styled from "styled-components";
// 独自定義のプロパティ
type CustomProps = {
hoge?: boolean;
};
const CustomButton = styled.button<CustomProps>`
color: ${(props) => props?.hoge? 'red': 'blue'};
`
これでCustomButtonにhogeというプロパティを渡すことで文字色を制御できるようになりました。
こういったケースの場合、カスタムしたプロパティは大概必須ではないと思います。
その場合はコンポーネントのdefaultPropsを指定して、初期値を決めておきましょう。
import React from "react";
import styled from "styled-components";
// 独自定義のプロパティ
type CustomProps = {
hoge?: boolean;
};
const CustomButton = styled.button<CustomProps>`
color: ${(props) => props?.hoge? 'red': 'blue'};
`
// hogeの初期値をfalseにしておく
CustomButton.defaultProps = {
hoge: false;
}
ここまでをまとめたサンプル
ここまでの内容をまとめたサンプルコードを以下に記します。
import React, { useCallback, useMemo, useState } from "react";
import styled from "styled-components";
// 基本的なstyled-componentsの使い方
const CustomButton = styled.button`
color: red;
font-weight: bold;
`;
// Propsの値によってスタイルを制御する例
// ここでは<p>のプロパティの1つであるchildrenを使っている
const CustomParagraph1 = styled.p`
color: ${(props) =>
props.children === "someFlg is True" ? "green" : "blue"};
`;
// 独自定義のプロパティ
type CustomProps = {
hoge?: boolean;
};
// 継承 + 拡張したプロパティを使う例
const CustomParagraph2 = styled(CustomParagraph1)<CustomProps>`
color: ${(props) => (props.hoge ? "pink" : "red")};
`;
// プロパティの初期値を設定することもできる
CustomParagraph2.defaultProps = {
hoge: false
};
const App: React.FC = () => {
const [someFlg, setSomeFlg] = useState(false);
const reverseFlg = useCallback(() => {
setSomeFlg((flg) => !flg);
}, []);
const label = useMemo(() => {
return someFlg ? "someFlg is True" : "someFlg is False";
}, [someFlg]);
return (
<div className="App">
<CustomButton onClick={reverseFlg}>フラグ書き換え</CustomButton>
<CustomParagraph1>{label}</CustomParagraph1>
<CustomParagraph2 hoge={someFlg}>CustomType Sample</CustomParagraph2>
</div>
);
};
export default App;
画面上のボタンを押下することで、stateの値が変化し、それに伴ってstyled-componentsから動的にスタイルが反映されるのが分かるかと思います。

まとめ
今回はReact + Typescriptの環境下でstyled-componentsを扱っていくTips的な内容をまとめました。
オブジェクトリテラルの記法に慣れていると、最初は取っ付きづらい印象を受けますが、アプリの規模が大きくなるにつれてスタイルの管理がしやすくなるかと思います。
今回の内容が参考になりましたら幸いです。
Discussion