Help us understand the problem. What is going on with this article?

styled-componentsを使った雑なReact Presentational Componentの書き方

More than 1 year has passed since last update.

最近、仕事でReactを書く機会が多くなってきて色々試しているうちに書き方が落ち着いてきました。

[注意]

本来はクラス毎にStyledComponentsのインスタンスを作った方がいいです。自分がVueライクな感じで雑に書くための記法です。

この表記ですと、子コンポーネントに同じクラス名があたったときに、親コンポーネントのスタイルが当たるので完全なscopedなスタイルにはなりません。
@nabeliwoさんにコメントいただきました。ありがとうございます!)

既にHTMLが存在しているときに雑にReactに移植するときの途中段階とかで役立つ書き方です

TodoItem.jsx
import React from 'react'
import styled from 'styled-components'

const TodoItem = ({
  className,
  title,
  description,
  onDestroy,
}) => (
  <div className={className}>
    <div className='title'>{title}</div>
    <div className='description'>{description}</div>
    <span className='close'></span>
  </div>
)

export default styled(TodoItem)`
  margin: 12px 0;
  padding-bottom: 12px;
  border-bottom: 1px solid #e5e5e5;

  .title {
    font-weight: bold;
    font-size: 15px;
  }

  .description {
    opacity: 0.8;
    font-size: 12px;
  }
`

ポイント

  • styled-componentsでCSSのsyntaxのままJS内に埋め込めるようになったこと
    • 今までCSS in JSはキャメルケースのスタイルが嫌だったので使ってなかった。
    • 少なくともVSCodeではプラグインがあってうまく動いてる
  • styled-componentsで作ったスコープの中でのみ効くスタイルを書く
    • CSS Modulesの考え方から
    • classNameに勝手に割り振ってくれて擬似的なスコープが出来る。
    • exportで吐き出す時に書いて、一箇所にスタイルをまとめる
      • 公式のサンプルでは各パーツごとに定数を定義していって、それを組み合わせる形にしているので推奨される書き方ではなさそう
    • 子コンポーネントに同じクラス名があたったときに、親コンポーネントのスタイルが当たるので完全なscopedなスタイルではない
  • HTML, CSS, JSが1ファイルになる
    • Vue.jsライクなファイル構成になる。半年前ぐらいまでVue.jsばっか書いてたから嬉しい
  • AtomicDesignの尺度とは違う。もう少しざっくり書く時に使える。
    • アプリケーションを作り始めるタイミングではこのぐらいのサイズ感で書くと早い(気がする)
  • Componentがでかくなるとファイルを分けたくなるので、小さく保つ意識が持てるかも

TypeScript

TodoItem.tsx
import * as React from 'react'
import styled from 'styled-components'

const TodoItem : React.StatelessComponent<{
  className?: string
  title?: string
  description?: string
  onDestroy?: Function
}> = ({
  className,
  title,
  description,
  onDestroy,
}) => (
  <div className={className}>
    <div className='title'>{title}</div>
    <div className='description'>{description}</div>
    <span className='close'></span>
  </div>
)

export default styled(TodoItem)`
  margin: 12px 0;
  padding-bottom: 12px;
  border-bottom: 1px solid #e5e5e5;

  .title {
    font-weight: bold;
    font-size: 15px;
  }

  .description {
    opacity: 0.8;
    font-size: 12px;
  }
`

Reactはv16、参考例のTypeScriptはv2.7を対象にしています。

mottox2
フロントエンドを中心にWebサービス・アプリを作ってるフリーランスエンジニア。UIデザインと編曲もやってます。
https://mottox2.com
admin-guild
「Webサービスの運営に必要なあらゆる知見」を共有できる場として作られた、運営者のためのコミュニティです。
https://admin-guild.slack.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away