[React] よーし! いっちょReactやってみっか! #6 スタイル編

2020.10.07

はじめに

CX事業本部の中安です。まいどです。

モバイルアプリエンジニアな自分がReactを始めてみることにした 「よーし! いっちょReactやってみっか!」シリーズの続きです。 今回もよろしくお願いします。

前回は、プロジェクトのデフォルト構成を一旦作り直してindex.jsの簡単な実装をしてみました。

今回はスタイルを当てる方法などをまとめてみたいなぁと思います。

スタイル直接指定

HTMLstyle属性を直接書くように要素のスタイルを書くことができます。

あくまでJSXなのでHTMLとは仕様が違うところがあります。 大きな違いとしてはJavaScriptオブジェクトを渡すことと、その中身はCSSでおなじみのケバブケースではなくキャメルケースで渡すことです。

簡単に書いてみるとこんな感じです。

const Hello = (props) => {
    let style = {
        backgroundColor: "gray",
        color: "#FFF",
        margin: 10,
        padding: 10,
    };
    return (
        <h1 style={style}>Hello World!</h1>
    )
}

marginpaddingには数字を直接渡すことができます。 これは勝手に数値の場合はpxとして扱ってくれるようです。 使うキーによってデフォルトの単位が決められているようで、 他の単位を指定したい場合は直接文字列(たとえば"100%"など)で書くことになるようです。

ではブラウザで確認してみましょう。

見事に見え方が変わりました。

ただし、このスタイルを直接書くという方法は、公式ドキュメントには

(中略) style 属性を要素のスタイリングの主要な手段として使うことは一般的に推奨されません。多くの場合、className を使って外部の CSS スタイルシートに定義された CSS クラスを参照するべきです。

と書かれていて、パフォーマンスの観点からしても推奨される手法ではないとのことです。 簡単なサンプルを作るなどではお手軽でいいと思いますが、実務的なプロダクトとなるとこの手法は避けるべきでしょうね。

クラス指定

従来のWEBアプリでもスタイル直接指定よりもクラスなどによるCSSでのスタイル指定が一般的ですね。 Reactでも同じようにクラス指定でのスタイル定義ができます。

ここもJSXだとHTMLと少しだけ仕様が違うようなので注意が必要です。

index.css

CSSファイルを作って、そこに先程のスタイル定義を移動させてみましょう。 まず、コマンドでCSSファイルを作ります。

% touch src/index.css

中を開いて編集しましょう。

index.css

.Hello-H1 {
    background-color: gray;
    color: #FFF;
    margin: 10px;
    padding: 10px;
}

あまりセンスのいい命名じゃないですが、クラス名はHello-H1にしてみました。

これは純粋なCSSなので、先程のキャメルケースからケバブケースに戻し、ダブルクォートで囲った箇所はそれを外し、数値には単位をつけます。もちろんセミコロンで仕切ってやる必要があります。

index.js

index.jsに戻って、先程スタイル指定をしていた箇所を削除します。

const Hello = (props) => {
    
    return (
        <h1>Hello World!</h1>
    )
}

次に、作ったCSSファイルをインポートしてやる必要があります。

import React, { useState } from 'react';
import ReactDOM from 'react-dom';
import './index.css';

同じ階層に配置しているので書き方としてはこんな感じでインポートします。

最後にCSSで定義したスタイルを反映させるのですが、「HTMLと少しだけ仕様が違う」と書いたように classという属性ではなくclassNameという属性でクラスを指定します。(classJavaScriptの予約語だからと思われます)

const Hello = (props) => {
    return (
        <h1 className="Hello-H1">Hello World!</h1>
    )
}

これでブラウザを確認してみましょう。

スタイル直接指定した時と同じ表示になると思います。

Bootstrapを使ってみる

CSSフレームワークのおなじみのものといえばBootstrapですねっ。 (え? Material-UI じゃないの? って声はひとまず置いておいて・・・またどこかでやりますから・・・)

ReactBootstrapを導入するにはどうしたらいいのでしょうね。

React Bootstrap

React用に最適化されたReact Bootstrapというものがあるようです。

React Bootstrapの特長としては

  • React用に再構築されている
  • 従来のBootstrapに含まれるjQueryなどの依存関係を取り払っている
  • Reactで使いやすいようにコンポーネント化されている

という感じらしいです。ちょっと使ってみたいですね。

導入

こういったライブラリを導入するのはこのシリーズで初めてなので、 ついでなのでnpmを使ってライブラリを導入する方法も確認してみたいと思います。

プロジェクトルートディレクトリにて以下のコマンドを打ちます。

% npm install react-bootstrap bootstrap

すると、インストールが始まりpackage.jsonファイルが更新されたかと思います。 npm installに取り入れたいライブラリ名をスペース区切りで羅列していくことで、必要なライブラリなどを簡単に取り込むことができるわけですね。

インポート

単純にページ全体にBootstrapのスタイルを適用するためには、以下のようにインポートを書いてやる必要があります。 こういうindex.jsのような全体に影響するJavaScriptファイルに1箇所だけ書くのがよいとのことです。

import React, { useState } from 'react';
import ReactDOM from 'react-dom';
import 'bootstrap/dist/css/bootstrap.min.css';
// import './index.css';

※先程のindex.cssのインポートは干渉してしまうので一旦コメントアウトしています。

これだけで見た目がパッと変わると思います。

HTMLに埋め込むパターン

スタイルだけを適用させるのならば、そもそものHTMLに書いてしまうという方法もあるようです。

public/index.htmlのヘッダ部分に<link>タグを使ってCDNリンクを埋め込む方法が紹介されています。

<!DOCTYPE html>
<html lang="en">
  <head>
    ...中略...
    <link
      rel="stylesheet"
      href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css"
      integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk"
      crossorigin="anonymous"
    />
    ...中略...
  </head>

※バージョン指定は古くなる可能性が高いのでこちらで確認ください。

React Bootstrap のコンポーネントを使う

いずれかの手法でBootstrapのスタイルを読み込んだ後に、 React Bootstrapのコンポーネント化された部品を使ってUI要素をリッチにすることができます。

ためしにButtonを使ってみますね。インポートを追加します。

import React from 'react';
import ReactDOM from 'react-dom';
import 'bootstrap/dist/css/bootstrap.min.css';
import Button from 'react-bootstrap/Button';

HTML埋め込みパターンであれば、3行目はなしでいいです。

レンダリングしているところをこんな感じに書き換えます。

let dom = document.getElementById('root');
ReactDOM.render(
<div className="card">
  <div className="card-body">
    <Button variant="outline-primary">プライマリーボタン</Button>
  </div>
</div>,
dom);

ちょっと見栄えよくしたいってことでcardとかで囲ってみましたが、書きたかったのは<Button>のところです。 variantという属性にどういうスタイルのボタン化を指定することができるようですね。

ブラウザを確認すると

お、Bootstrap的なボタンが表示されました。

Bootstrapを使ったことがある方ならおなじみですが、primaryの他にもsecondarysuccessdarkなどが指定できますし、 上のようにoutline-をつけると枠線だけになります。

では、レンダリングされたUIはどのようになっているかをブラウザで確認してみると

<div id="root">
  <div class="card">
    <div class="card-body">
      <button type="button" class="btn btn-outline-primary">プライマリーボタン</button>
    </div>
  </div>
</div>

こういうHTML構成にレンダリングされていました。 変更したいbtn-*のところだけを書くことができるので良いですね!

今回はボタンだけを試しましたが、React Bootstrapではもっと沢山のコンポーネントが用意されています。 他のコンポーネントについてはこちらのリンク先の左ペインからお好みのものを探してください。

ちなみに先程の例でいうと、カードもコンポーネントとして用意されているので、下記のように書き換えることができますね。

import React from 'react';
import ReactDOM from 'react-dom';
import 'bootstrap/dist/css/bootstrap.min.css';
import Button from 'react-bootstrap/Button';
import Card from 'react-bootstrap/Card';

let dom = document.getElementById('root');
ReactDOM.render(
  <Card>
    <Card.Body>
      <Button variant="outline-primary">プライマリーボタン</Button>
    </Card.Body>
  </Card>,
dom);

インポートの書き方の補足

公式のインポートによる記載なのですが

You should import individual components like: react-bootstrap/Button rather than the entire library. Doing so pulls in only the specific components that you use, which can significantly reduce the amount of code you end up sending to the client.

ライブラリ全体ではなく「react-bootstrap/Button」のように部分的にインポートすべきです。指定の使用するコンポーネントのみを取り込むことで、最終的にクライアントに送信するコードの大幅な量の削減ができるようになります。

import Button from 'react-bootstrap/Button';

// or less ideally
import { Button } from 'react-bootstrap';

と、2種類の方法が記載されていました。

1つめの方法はreact-bootstrapButtonコンポーネントだけがインポートされる書き方になり、 2つめの方法はreact-bootstrap全体を取り込んだ上でButtonをインポートする流れに現時点ではなるそうです。 (将来的には変わる可能性があるとのこと)

ですので、今回は1つめの方法を採用しました。

最後に

ということで、今回はスタイルの当てかたを色々ためしてみました。 また、npmコマンドを用いてReact Bootstrapをインストールし、使ってみるところまでをやりました。

スタイルについては、仕様の違いはあれど純粋なHTML+CSSのときと書き方や考え方は異ならないようですね。 Reactを初めて触るWEBエンジニアの方でもあまり違和感は感じないのではないでしょうか。

次回は「状態管理・ステート」あたりを触っていきましょうか。

では、またー。