Reactのアプリケーションでstyled-componentsを使ってやったこと

Reactのアプリケーションでstyled-componentsを使ってやったこと

業務でReactのアプリケーションにstyled-componentsを使うことにしました。その際に、やったことなどを簡単にまとめたいと思います。

Ads

styled-componentsにした理由

  1. cssを書くのと同じようにjs内に書ける
  2. テーマが使える
  3. スタイルのextendができる

この辺がいいなーと思ってstyled-componentsを使うことにしました。

今回やったこと

  1. 画面によってスタイルを変更できるようにする
  2. propsによってスタイルを変更できるようにする
  3. styleの上書きをして拡張できるようにする

以上3点です。あとはReactで言えばcomponent作るのとほぼほぼ同じです。なので、以上のことを中心に今回は記事にしてます。
おまけでこんな時どうするっていうのも記事してます。

画面によってスタイルを変更できるようにする

例えば、ユーザー画面と管理画面とかでボタンの色などを変えたい場合があると思います。その際に、styled-componentsにはthemeを渡すことができるので簡単に実現することができます。

基本的な使い方として、styled-componentsThemeProviderというのがあってそのthemeに対してcolorとかfontとか変数として持たしたい物を渡せばcomponentでthemeを受け取ることができます。

common/styles/Variables.js

export const variables = {
  font: "Yu Gothic", "Hiragino Kaku Gothic ProN", Meiryo, Arial, sans-serif',
  color: {
    primary: "blue",
    caution: "red"
  },
  text: "white"
}
import {valiables} from 'common/styles/Variables'

render(
  <div>
    <Button>Normal</Button>

    <ThemeProvider theme={valiables}>
      <Button>Themed</Button>
    </ThemeProvider>
  </div>
);

export const Button = styled.button`
  ${({theme}) => css`
    background: ${theme.color.primary};
    color: ${theme.text};
  `}
`

上記を見るとわかるようにThemeProviderthemevariablesを渡すことでstyled-componentsを定義するとこでthemeを使うことができます。

基本的な使い方だとこれでいいと思うんですけど、ユーザー画面と管理画面みたいにまとめて変えたい場合、いちいちcomponentごとにThemeProviderでwrapしなきゃいけなさそうですが、
実はそんなことありません。というのもThemeProviderでwrapされていればその子要素全てにthemeを渡すことができます。

アプリケーションの大元となるcomponentに対してThemeProviderを適用すればthis.props.childrenにあるもの全てにthemeを渡せます。

admin/App.js or user/App.js

import palette from '../styles/variables'


render() {
  return (
    <Router>
      <ThemeProvider theme={palette}>
        <div>
          {this.props.children}
        </div>
      </ThemeProvider>
    </Router>
  )
}

あとは、ユーザー画面と管理画面ごとにcommon/styles/Variablesを上書きするメソッドを作れば良いわけです。
例えばこんな感じで

import {valiables} from 'common/styles/Variables'

const palette = () => {
  return override(valiables)
}

const override = (obj) => {
  const p = obj
  p.color = Object.assign(p.color, {primary: "green"})
  return p
}

export default palette

最近のフロントエンドのCSSの事情からすると変数を持たせるのって当たり前になってきていて、というか無いときついっすね。そういった意味で、styled-componentってCSSを書くは書くんですけど、基本はJavaScriptなので変数を持たせる、上書きするっていうのも簡単にできるのはいいですよね!CSSをJSライクに使う感じでなんでもできてしまう印象です。

propsによってスタイルを変更できるようにする

渡すpropsによってstyleを変更するのも簡単にできます。ていうか、これができないとReactのcomponentとして使うことできないけど。。。

<Button displayBlock={true}>ボタン</Button>
render(){
  const {displayBlock, color, children} = this.props
  return(
    <ScButton
      options={{color, displayBlock}}
      type={"button"}
    >
      {children}
    </ScButton>
  )
}

export const ScButton = styled.button`
  ${({theme}) => css`
    background: ${theme.color.primary};
    color: ${theme.text};
  `}
  ${({options}) => options.displayBlock ? css`
    display: block;
  `: css`
    display: inline-block;
  `}
`

これでdisplayBlockの状態によってスタイルの出しわけができます。あと、先ほどのテーマのvariables.jsを組み合わせるともっと強力にスタイルを出し分けることができます。
例えば渡すpropsによってボタンの色を変更するなどですね。

これはcolorcautionを渡しています。

<Button color="caution" displayBlock={true}>ボタン</Button>

次に、colorの出しわけができるようにちょっと改良します。この辺もjsを使ってcssを書けるのでif elseが使えます。

const ScButton = styled.button`
  ${({theme}) => css`
    font-size: 16px;
    color: ${theme.text};
  `}
  ${({theme, options}) => options.color ? css`
    background: ${theme.color[options.color]};
  `: css`
    background: #f1f1f1;
  `}
  ${({options}) => options.displayBlock ? css`
    display: block;
  `: css`
    display: inline-block;
  `}
`

これでdefaultカラーとpropsで渡したカラーを使うことができます。ちなみに、メソッドで分離することも可能です。

const ScButton = styled.button`
  ${({theme}) => css`
    font-size: 16px;
    color: ${theme.text};
  `}
  ${({theme, options}) => getButtonColor({theme: theme, options: options})
  ${({options}) => options.displayBlock ? css`
    display: block;
  `: css`
    display: inline-block;
  `}
`

const getButtonColor = ({theme, options}) => {
  if(options.color) {
    background: ${theme.color[options.color]};
  }else {
    background: #f1f1f1;
  }
}

こっちの方が、メインとなるスタイルがスッキリしますね。

styleの上書きをして拡張できるようにする

共通で使えるようにcomponentを作りますが、時としてここでは若干スタイルを変更したいなどのことが起きます。絶対!
styled-componentsでは既存のstyle-componentsを定義したcomponentに対してスタイルを上書きすることができます。自分的にはstyled-componentsの一番強力な部分などでは無いかなと思います。Extendsという機能を使ってスタイルの上書きができます。

その際の注意点としてstyledComponentを定義する際にimportできるように設計してください。先ほどのボタンスタイルにexportを追記します。

export const ScButton = styled.button`
  ${({theme}) => css`
    font-size: 16px;
    color: ${theme.text};
  `}
  ${({theme, options}) => getButtonColor({theme: theme, options: options})
  ${({options}) => options.displayBlock ? css`
    display: block;
  `: css`
    display: inline-block;
  `}
`

const getButtonColor = ({theme, options}) => {
  if(options.color) {
    background: ${theme.color[options.color]};
  }else {
    background: #f1f1f1;
  }
}

ですが、例えばここで使っているSubmitボタンについてはfont-size: 18px;で太字にもしたいっていう場合どうするかというと

contents.js

import {ScButton} from './Button'



render(){
  return(
    <div>
      <h1>コンテンツ</h1>
      <ExtendButton color="caution">ExtendButton</ExtendButton>
    </div
  )
}


export const ExtendButton = ScButton.extend`
  ${({theme}) => css`
    font-weight: bold;
    font-size: 18px;
  `}
`

これだけでスタイルの上書きができます。これで、共通で作ったcomponentを部分的に拡張して使うことができます。

styled-componentsを使っていてこんな時どうする

React-routerのLinkを使いたい場合

HTMLの要素を指定してにstyled-componentsを適用するのが基本的な書き方ですよね。例えば

const StyledButton = styled.button`
・・・
`

って感じです。ですがreact-routerなどのように外部ライブラリーを使う場合には、下記のように書けばstyleを適用することができます。

import {Link} from 'react-router-dom'
import styled, {css} from "styled-components"

export const ScLinkBtn = styled(Link)`
  ・・・
`

メディアクエリーを使いたい場合

レスポンシブデザインでは必須のメディアクエリーですが、メディアクエリー用のメソッドを作っておけば、簡単にメディアクエリーを各コンポーネントで使うことができます。

Helper.js

import { css, keyframes } from 'styled-components'

export const media = {
  desktop: (...args) => css`
    @media (min-width: 992px) {
      ${ css(...args) }
    }
  `,
  tablet: (...args) => css`
    @media (min-width: 768px) {
      ${ css(...args) }
    }
  `,
  phone: (...args) => css`
    @media (max-width: 576px) {
      ${ css(...args) }
    }
  `
}
import styled, {css} from "styled-components";
import {media} from './Helper'

const Content = styled.div`
  height: 3em;
  width: 3em;
  ${media.desktop`background: red;`}
  ${media.tablet`background: green;`}
  ${media.phone`background: blue;`}
`;

キーフレームアニメーションやりたい場合

styled-componentsでキーフレームアニメションをする場合にはstyled-componentsのkeyframesを使います。

import styled, {css, keyframes} from "styled-components"

export const rotate360 = keyframes`
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
`

export const Content = styled.i`
  ${({theme}) => css`
    font-size:  24px;
    display: inline-block;
    animation: ${rotate360} 1s linear infinite;
  `}
`

こういったアニメーションって複数使ったりしますよね。例えば、フェードインとかフェードアウトとか。アニメーションもHelper.jsとかでまとめてしまって、呼び出して使うのが良さそうです。

まとめ

ざっくりこんな感じstyled-componentsを使ってみました。とりあえずはいい感じにできました。
今後運用しながらまた改良していくので、その際にも記事にできればと思います。

こんなんもあるよ

参考

いいなと思ったらシェアお願いします

同じタグで検索

Ads
ページの先頭へ