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 themakeStyles()
API. If you are wondering which you should use, we would encourage the use ofmakeStyles()
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
に渡されます。
-
戻り値
-
hook
スタイルシートのオブジェクトをつくるフック関数です。関数コンポーネントの中でも使えます(「関数コンポーネントとクラスコンポーネント」参照)。オプションの引数には、スタイルシートで用いるプロパティを納めたオブジェクトが渡せます。
CSSのスタイルをJavaScriptのオブジェクトに移す
create-react-app
でつくられたReactアプリケーション(src/App.js
)に、makeStyles()
をimport
します。そして、CSSファイル(src/App.css
)は除いてしまいましょう。これで、一旦スタイルシートは適用されなくなりました。
// import './App.css';
import { makeStyles } from '@material-ui/styles';
まずは、CSSファイル(src/App.css
)からクラス(App
)の定めをひとつ、JavaScriptコードに移してみます。
.App {
text-align: center;
}
関数の引数に渡すスタイルシートはオブジェクトで定めます。クラス名はプロパティとし、設定は入れ子のオブジェクトです。その中にプロパティと文字列の設定値を加えるかたちになります。
const フック関数 = makeStyles({
クラス: {
プロパティ: 文字列の設定値,
// 他のプロパティの定め
},
// 他のクラス
});
テーマを参照する場合には、スタイルシートを関数で定めます。引数にテーマ(theme
)を受け取り、戻り値がスタイルシートオブジェクトです。
const フック関数 = makeStyles((theme) => ({
クラス: {
プロパティ: 文字列の設定値,
// 他のプロパティの定め
},
// 他のクラス
}));
今回は、簡単にオブジェクトで定めましょう。ここで、JavaScriptのプロパティにはハイフン(-
)が使えないことにご注意ください。以下のようにクラスやプロパティのハイフンは除いて、キャメルケースにしなければなりません。そのスタイルシートをmakeStyles()
の引数にして呼び出すと、フック関数(useStyles
)が得られます。
関数コンポーネントの中でフック関数を呼び出せば、class
オブジェクトがつくられられます。スタイルシートに定めたクラスの参照を取り出して、render()
が返すマークアップ(テンプレート)のclassName
属性に与えればよいのです。
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
)はあとに回します。
.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の値が文字列、そしてプロパティはカンマ(,
)区切りになることに注意してください。
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 キーフレーム名
までをひとつの文字列としてスタイルオブジェクトのプロパティに定めてください。
.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。
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
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;
-
JSSのバージョンによっては、
$
をつけないこともあるようです(「Do keyframe animations work?」参照)。 ↩