LoginSignup
98
63

More than 3 years have passed since last update.

React: Material-UI 4.0のコンポーネントへのCSS設定はwithStyles()からmakeStyles()に

Last updated at Posted at 2019-06-05

Material-UIは、Googleの提唱するマテリアルデザインを実装したReactコンポーネントです。また、CSSのスタイルシートをJavaScriptコードに書き込むCSS-in-JSを採用しました。そして、そのスタイルシートをコンポーネントに提供する関数がmakeStyles()です。本稿では、この関数を使って、Reactの簡単なアプリケーションの関数コンポーネントにスタイルシートを定めてみます。

これまでスタイルの定めには、コンポーネントをラップするwithStyles()関数が用いられました(「React: Material-UIのwithStyles()でCSSをJavaScriptコードに定める」参照)。けれど、公式サイトのblog記事「March 2019 Update」では、できるだけmakeStyles()を使うことが推奨されています。

We have migrated a few demos from the withStyles() API to the makeStyles() API. If you are wondering which you should use, we would encourage the use of makeStyles() where possible.

ひな形のアプリケーションにインストールする

Reactアプリケーションのひな形は、create-react-appでつくりましょう。コマンドラインツールからつぎのように入力します。

$ npx create-react-app my-app

アプリケーション(my-app)のディレクトリに切り替えたら、つぎにmaterial-uiをインストールしてください。

$ npm install @material-ui/core

これで、Material-UIを使う準備が整いました。

makeStyles()の構文

ReactコンポーネントにJavaScriptのオブジェクトで定めたスタイルシートを提供する関数makeStyles()の構文を先にご紹介しましょう。

makeStyles(styles, [options]) => hook

戻り値の関数から、コンポーネントに関連づけるスタイルシートのオブジェクトがつくられます。

引数

  • styles(Function | Object)
    スタイルをつくる関数、またはスタイルオブジェクトです。コンポーネントに関連づけられます。テーマを参照する場合には、関数で定めて、第1引数に渡してください。
  • options(Object[省略可能])
    • options.defaultTheme(Object[省略可能]): デフォルトのthemeオブジェクトです。ThemeProviderから提供されない場合に用いられます。
    • options.withTheme(Boolean[省略可能]): themeオブジェクトをコンポーネントにプロパティとして与えるかどうかの論理値です(デフォルト値はfalse)。
    • options.name(String[省略可能]): スタイルシートの名前です。デバッグに役立ちます。値がなければ、コンポーネント名へのフォールバックが試みられます。
    • options.flip(Boolean[省略可能]): falseにすると、スタイルシートのrtl(Right-to-left)変換はオプトアウトされます。trueは、スタイルが左右反転します。nullの場合は、theme.directionにしたがいます。
    • その他のキーは、jss.createStyleSheet([styles], [options])の引数optionsに渡されます。

戻り値

CSSのスタイルをJavaScriptのオブジェクトに移す

create-react-appでつくられたReactアプリケーション(src/App.js)に、makeStyles()importします。そして、CSSファイル(src/App.css)は除いてしまいましょう。これで、一旦スタイルシートは適用されなくなりました。

src/App.js
// import './App.css';
import { makeStyles } from '@material-ui/styles';

まずは、CSSファイル(src/App.css)からクラス(App)の定めをひとつ、JavaScriptコードに移してみます。

src/App.css
.App {
  text-align: center;
}

関数の引数に渡すスタイルシートはオブジェクトで定めます。クラス名はプロパティとし、設定は入れ子のオブジェクトです。その中にプロパティと文字列の設定値を加えるかたちになります。

const フック関数 = makeStyles({
  クラス: {
    プロパティ: 文字列の設定値,
    // 他のプロパティの定め
  },
  // 他のクラス
});

テーマを参照する場合には、スタイルシートを関数で定めます。引数にテーマ(theme)を受け取り、戻り値がスタイルシートオブジェクトです。

const フック関数 = makeStyles((theme) => ({
  クラス: {
    プロパティ: 文字列の設定値,
    // 他のプロパティの定め
  },
  // 他のクラス
}));

今回は、簡単にオブジェクトで定めましょう。ここで、JavaScriptのプロパティにはハイフン(-)が使えないことにご注意ください。以下のようにクラスやプロパティのハイフンは除いて、キャメルケースにしなければなりません。そのスタイルシートをmakeStyles()の引数にして呼び出すと、フック関数(useStyles)が得られます。

関数コンポーネントの中でフック関数を呼び出せば、classオブジェクトがつくられられます。スタイルシートに定めたクラスの参照を取り出して、render()が返すマークアップ(テンプレート)のclassName属性に与えればよいのです。

src/App.js
const useStyles = makeStyles({
  app: {
    textAlign: 'center'
  }
});

function App() {
  const classes = useStyles();
  return (
    // <div className="App">
    <div className={classes.app}>

    </div>
  );
}

これで、JavaScriptコードに定めたCSSのクラスがひとつReactアプリケーション(src/App.js)に割り当てられました。同じ要領で、CSSファイル(src/App.css)の他のクラスも移していきましょう。ただし、animationが使われているクラス(App-logo)はあとに回します。

src/App.css
.App-header {
  background-color: #282c34;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: calc(10px + 2vmin);
  color: white;
}

.App-link {
  color: #61dafb;
}

クラスとプロパティの名前はキャメルケースにし、CSSの値が文字列、そしてプロパティはカンマ(,)区切りになることに注意してください。

src/App.js
const useStyles = makeStyles({

  appHheader: {
    backgroundColor: '#282c34',
    minHeight: '100vh',
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'center',
    justifyContent: 'center',
    fontSize: 'calc(10px + 2vmin)',
    color: 'white'
  },
  appLink: {
    color: '#61dafb'
  }
});

function App() {
  const classes = useStyles();
  return (
    <div className={classes.app}>
      {/* <header className="App-header"> */}
      <header className={classes.appHheader}>

        <a
          // className="App-link"
          className={classes.appLink}

        >

        </a>
      </header>
    </div>
  );
}

これで、アニメーションする要素(<img>)以外のスタイルは整いました。

animationを定める

animationプロパティには@keyframes規則が加えられています。これは、
@keyframes キーフレーム名までをひとつの文字列としてスタイルオブジェクトのプロパティに定めてください。

src/App.css
.App-logo {
  animation: App-logo-spin infinite 20s linear;
  height: 40vmin;
  pointer-events: none;
}

@keyframes App-logo-spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

@keyframes規則の中身は、つぎのように入れ子のオブジェクトです。パーセンテージ(%)を用いる場合には、はじめが数字になるため文字列で定めなければなりません。そして、animationプロパティに定める@keyframes規則の名前には、頭に$印をつけてください(JSS「Keyframes Animation」)1

src/App.js
const useStyles = makeStyles({

  appLogo: {
    animation: '$App-logo-spin infinite 20s linear',
    height: '40vmin',
    pointeEvents: 'none'
  },

  '@keyframes App-logo-spin': {
    from: {
      transform: 'rotate(0deg)'
    },
    to: {
      transform: 'rotate(360deg)'
    }
  }
});

function App() {
  const classes = useStyles();
  return (
    <div className={classes.app}>
      <header className={classes.appHheader}>
        {/* <img src={logo} className="App-logo" alt="logo" /> */}
        <img src={logo} className={classes.appLogo} alt="logo" />

      </header>
    </div>
  );
}

これでひな形Reactアプリケーションのスタイルシートが、すべてJavaScriptコードに移せました。CSSファイル(src/App.css)はもう要りません。JavaScriptファイル(src/App.js)の中身を改めてつぎのコード001にまとめて掲げます。

コード001■src/App.js

src/App.js
import React from 'react';
import logo from './logo.svg';
import { makeStyles } from '@material-ui/styles';

const useStyles = makeStyles({
  app: {
    textAlign: 'center'
  },
  appLogo: {
    animation: '$App-logo-spin infinite 20s linear',
    height: '40vmin',
    pointeEvents: 'none'
  },
  appHheader: {
    backgroundColor: '#282c34',
    minHeight: '100vh',
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'center',
    justifyContent: 'center',
    fontSize: 'calc(10px + 2vmin)',
    color: 'white'
  },
  appLink: {
    color: '#61dafb'
  },
  '@keyframes App-logo-spin': {
    from: {
      transform: 'rotate(0deg)'
    },
    to: {
      transform: 'rotate(360deg)'
    }
  }
});

function App() {
  const classes = useStyles();
  return (
    <div className={classes.app}>
      <header className={classes.appHheader}>
        <img src={logo} className={classes.appLogo} alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className={classes.appLink}
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

  1. JSSのバージョンによっては、$をつけないこともあるようです(「Do keyframe animations work?」参照)。 

98
63
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
98
63