Reactのプロジェクトならstyled-components使うのがいいかも

昨日から自分が所属している会社のユニットメンバー5人日替わりで個人ブログを更新していこうという取り組みをしていくことになりました。 第一回の記事です。

ブログをローテーションで書いていくことの良さが記載してあります。 チームで行う取り組みなので個々人に責任感が生まれ強制力が働き良い取り組みだと思います。

というわけで今回は自分の番ということなので書いていきます!

タイトルにもあるようにstyled-componentについて説明をしていきます。

と、その前にcssのことについて軽く触れておきます。

cssの問題点

  • グローバルスコープ
  • 誰でも簡単に書けてしまう自由さ
  • どこに誰がどのような目的で書いたかわからなくなるときがある

などが挙げられると思います。 「グローバルスコープ」であるからこそクラス名が被らないような命名を考える時間などのコストが発生します。「誰でも簡単に書けてしまう」ということからFLOCSSやSMACSS、 RSCSSなどのフレームワークが登場し、記述するためのルールなどを設けてある程度記述する自由さに制限を与えていると思います。フレームワークの学習コストがそこまで高い訳ではないですが、実際に業務で導入してみないとメリット・デメリットがわからず、プロジェクトメンバー間での理解度にも差が生まれてきてしまいます。

cssは簡単だわー。」とか言われがちですが規模のあるプロジェクトなど運用していくことを考えると非常に難易度が上がると考えています。

このような問題をより解決に導くツールとしてstyled-componentsがあります。 styled-componentsは簡単にいうとjsの中でcssを記述することができるCSS in JSのライブラリの一つでReactのプロジェクトでは利用されることが多いようです。

styled-componentsの良いところ

  • コンポーネント単位でスコープが生成される
  • コンポーネント単位でcssが管理されているからスタイルを探すのに時間が掛からない
  • autoprefixerが自動で付与される
  • cssにjsの値を渡すことができる

大まかにこんな感じです。 実際にコードを交えながら一つ一つ見ていきましょう!

今回はcreate-react-appを使ってプロジェクトフォルダを作成します。

create-react-app styled-components_practice

styeled-componentsをインストールします。

yarn add styled-components

その後、App.jsを編集します。

import React, { Component } from 'react';
import styled from 'styled-components';
import HelloButton from './HelloButton';
import logo from './logo.svg';

class App extends Component {
  render() {
    return (
      <Wrapper>
        <Logo><img src={logo} alt="logo"/></Logo>
        <Title>Hello, styled-components!!!</Title>
        <HelloButton />
      </Wrapper>
    );
  }
}

const Wrapper = styled.div`
  background: #323232;
  padding: 20px;
  height: 100vh;
  text-align: center;
`;

const Logo = styled.p`
  width : 100px;
  margin: 0 auto;
  img {
    width: 100%;
  }
`;

const Title = styled.h1`
  color: #fff;
  font-family: "Meiryo";
  text-align: center;
  margin: 0;
  font-weight: lighter;
`;

export default App;

新たにHelloButton.jsファイルを作成して下のように記述してください。

import React, { Component } from 'react';
import styled from 'styled-components';

class HelloButton extends Component {
  render() {
    return (
      <Button>Click</Button>
    );
  }
}

const Button = styled.button`
  margin: 0 auto;
  width: 150px;
  border: none;
  padding: 18px;
  border-radius: 56px;
  font-size: 18px;
  font-weight: lighter;
  margin-top: 30px;
  cursor: pointer;
`;

export default HelloButton;

実際にローカルサーバーを立ち上げると、以下のようにブラウザに表示されると思います。

f:id:top_men:20180725014329p:plain

では

コンポーネント単位でスコープが生成される

ちゃんと上記のようにスコープが生成されているか確かめてみます。

f:id:top_men:20180725014833p:plain

styled-componentsが良い感じにクラス名が被らないように、ランダムな文字列を入れてくれています。 よげそうですね!

また

コンポーネント単位でcssが管理されているからスタイルを探すのに時間が掛からない

こちらもファイルを見てわかるようにコンポーネントごとにクラスを定義しているので何がどこに書いてあるのか素早く探し出すことができます!

次に検証するのがこちらです。

autoprefixerが自動で付与される

HelloButton.jsのファイルを編集します。 以下のスタイルを追加してください。

const Button = styled.button`
  margin: 0 auto;
  width: 150px;
  border: none;
  padding: 18px;
  border-radius: 56px;
  font-size: 18px;
  font-weight: lighter;
  margin-top: 30px;
  cursor: pointer;
  display: flex; // 追加箇所
  justify-content: center; // 追加箇所
`;

再度ブラウザの検証ツールを確認します。

f:id:top_men:20180725020040p:plain

なんと自動でベンダープレフィクスが付与されています! autoprefixerを別途インストールする必要もありませんね!

では最後に

cssにjsの値を渡すことができる

こちらを検証してみます!

その前に自分はVue.jsの単一ファイルコンポーネントを使ってjs側でrailsから取得した画像名をcssのbackgroundプロパティのurlに指定したいと思ったときがありました。 単一ファイルコンポーネントの場合、jsの変数などをstyleタグの中に渡すことができません。このようなかゆいところをstyled-componentsのテンプレート文字列が解決してくれます!

見ていきましょう。

ここではボタンの背景色をpropsによって変更するといったことをしてみます。

まずApp.jsでChildコンポーネントにpropsを渡してあげます。

import React, { Component } from 'react';
import styled from 'styled-components';
import HelloButton from './HelloButton';
import logo from './logo.svg';

class App extends Component {
  render() {
    return (
      <Wrapper>
        <Logo><img src={logo} alt=""/></Logo>
        <Title>Hello, styled-components!!!</Title>
        <HelloButton status="success" />
      </Wrapper>
    );
  }
}

const Wrapper = styled.div`
  background: #323232;
  padding: 20px;
  height: 100vh;
  text-align: center;
`;

const Logo = styled.p`
  width : 100px;
  margin: 0 auto;
  img {
    width: 100%;
  }
`;

const Title = styled.h1`
  color: #fff;
  font-family: "Meiryo";
  text-align: center;
  margin: 0;
  font-weight: lighter;
`;


export default App;

HelloButton.jsの方でpropsを受け取ってpropsに応じて背景色を変更するロジックを書きます。テンプレート文字列の中で${この中でロジック}を使います。

import React, { Component } from 'react';
import styled from 'styled-components';

class HelloButton extends Component {
  render() {
    return (
      <Button {...this.props}>Click</Button>
    );
  }
}

const Button = styled.button`
  margin: 0 auto;
  width: 150px;
  border: none;
  padding: 18px;
  border-radius: 56px;
  background: ${(props) => {
    return props.status === "success" ? "green" : "red"
  }};
  color: #fff;
  font-size: 18px;
  font-weight: lighter;
  margin-top: 30px;
  cursor: pointer;
  display: flex;
  justify-content: center;
`;

export default HelloButton;

f:id:top_men:20180725031512p:plain

このように表示されればOKです! propsで受けとった値をcssに渡すことができました。

まとめ

テンプレート文字列で書いていくのは最初違和感がありましたが、それ以上に大きなメリットを感じることができたため積極的に使っていこうと思いました。またFLOCSSなどのフレームワークを全くなくすということはせず、併用していくことは全然ありだと感じました。