「ランサーズ Advent Calendar 2018」9日目の記事になります。
昨日は、「ランサーズでインターンをして感じたプログラミング学習における個人とチームの違い」でした。
ランサーズはいくつかReactのプロダクトがあるのですが、スタイルはcss-modulesを使用して書いていました。
最近Reactの開発にstyled-componentsを採用したところ、非常に書き心地が良かったので紹介します。
styled-componentsとは
styled-copmonentsはJavaScriptのファイルの中でcssを定義するためのライブラリで、いわゆるCSS in JSの一種です。
styled-componentsはstyled.[タグ名]`[css]`でスタイルをあてたコンポーネントを作成することができます。
作成したコンポーネントは変数名をタグ名にして使うことができます。
import styled from "styled-components";
const Title = styled.h1`
font-size: 30px;
color: red;
`;
const App = () => (
<Title>タイトル</Title>
)
ちなみにstyled.h1にテンプレートリテラル(``)が続いている構文が見慣れないかもしれないですが、これはタグ付きテンプレートリテラルと呼ばれる構文です。
コンポーネントを作ってみる
styled-componentsを使って下の画像のようなボタンのコンポーネントを作ってみます。
このボタンはdefault・Primary・Dangerの三種類の色があります。
また大きさが2種類、disabledとそうではないパターンが存在します。
最終的なコードはこちらに置いてあります。
共通部分をつくる
はじめにdefaultのボタンを作り、すべてのパターンに共通する箇所のスタイルをあてます。
ここでは、フォントのサイズや丸みをつけたり、ホバー時のカーソルがポインターになるようにしています。
const Button = styled.button`
font-size: 1rem;
padding: 5px 10px;
border-radius: 5px;
cursor: pointer;
`;
const App = () => (
<div>
<Button>Button</Button>
</div>
)
色を変える
次に色を変えてみます。
今回はdefaultとPrimary、Dangerの3タイプのボタンが使えるようにします。
const Button = styled.button`...`;
const PrimaryButton = styled(Button)`
border: none;
color: white;
background: #007bff;
`;
const DangerButton = styled(Button)`
border: none;
color: white;
background: #dc3545;
`;
const App = () => (
<div>
<Button>Button</Button>
<PrimaryButton>Primary</PrimaryButton>
<DangerButton>Danger</DangerButton>
</div>
)
styled([コンポーネント名])
で既存のコンポーネントに対してstyleを追加することができます。
ここではdefaultのbuttonにbackgroudやcolorを追加して新しいコンポーネントPrimaryButton
,DangerButton
を作っています。
大きさを変える
defaultのサイズに加えて、大きいサイズのボタンが使えるようにします。
コンポーネントのpropsにlargeを与えることでサイズを変更できるようにします。
const Button = styled.button`
font-size: 1rem;
padding: ${props => (props.large ? "10px 15px" : "5px 10px")};
border-radius: 5px;
cursor: pointer;
`;
const PrimaryButton = styled(Button)`..`;
const DangerButton = styled(Button)`...`;
const App = () => (
<div>
<div>
...
</div>
<div>
<Button large>Button</Button>
<PrimaryButton large>Primary</PrimaryButton>
<DangerButton large>Danger</DangerButton>
</div>
</div>
)
cssはテンプレートリテラルを使って記述するので${}
の中に変数などを入れることができます。
またstyled-componentsで${}
の中に関数を与えることもでき、第一引数はコンポーネントのpropsになります。
上のコードではpropsにlargeが与えられた場合とそうでない場合で、paddingを変えています。
disabledのときにスタイルを変える
ボタンがdisabledのときに色とカーソルの形状を変えます。
大きさを変えるときと同様にpropsにdisabledが与えられたときにスタイルを変えます。
import styled, { css } from 'styled-components';
const Button = styled.button`
...
${props => props.disabled && disabledCss}
`;
const disabledCss = css`
opacity: 0.5;
cursor: default;
`;
const PrimaryButton = styled(Button)`..`;
const DangerButton = styled(Button)`...`;
const App = () => (
<div>
...
<div>
<div>
<Button disabled>Button</Button>
...
</div>
<div>
<Button large disabled>Button</Button>
...
</div>
</div>
</div>
)
css``はcssを変数化して、そのcssをテンプレートリテラル内に挿入したい場合に使います。
ここではdisabledの場合のスタイルを変数化して、propsのdisabedが存在した場合に挿入しています。
これで完成です。
css-modulesとの比較
同じものをcss-modulesで作ろうとすると下のようになると思います。
import React from 'react';
import styles from './styles.css';
function createButton(type) {
return ({children, large, disabled}) => {
const classNameList = [styles.button, styles[type]]
if (large) {
classNameList.push(styles.large)
}
if (disabled) {
classNameList.push(styles.disabled)
}
return (
<button className={[styles.button]}>{children}</button>
)
}
}
const Button = createButton('default');
const PrimaryButton = createButton('primary');
const DangerButton = createButton('danger');
比較をするとstyled-componentsには以下のような利点があると考えます。
- styled-componentsの中だけで完結する。簡単なコンポーネントであればreactをimportする必要すらない。
- css-modulesでスタイルを変えることは最終的にclassNameに与える文字列をどうやって生成するかに帰着する。そのためこのような簡単なコンポーネントでも複雑なロジックが発生する。styled-componentでは複雑化しない。
- 一つのファイルで完結するので見通しが良い。
まとめ
styled-componentsを使ってボタンのコンポーネントを作成しました。
css-modulesと比較をすると簡潔なコードでコンポーネント作成ができていることがわかると思います。
以上、「ランサーズ Advent Calendar 2018」9日目の記事でした。
明日は「ランサーズエンジニアのキーボードの世界」です。お楽しみに!