React入門 ~Material UI編~

React入門記事、第4弾。
今回はUIコンポーネントを提供するMaterial UIのお話です。

※この記事はQiitaからの転載です。

Material UIとは? #

公式:Material UI
GoogleのMaterialデザインをベースに開発された、UIコンポーネントライブラリです。

お手軽にMaterialデザインを取り入れられることに加えて、コンポーネントの種類が豊富に用意されているため、それらを組み合わせるだけでも見栄えの良いものを作ることができます。
一からコンポーネントを作るのはつらいとか、デザインを考えるのが難しいとか、それらに工数をあまりかけたくないなどの場合にもおすすめです。

React向けのUIコンポーネントライブラリはいろんなものがありますが、その中で人気の高いライブラリでもあります。

執筆時点でのリポジトリスター数

こちらの記事でUIコンポーネントライブラリの紹介をされています。
早く・それなりの UI を実現する React コンポーネントセット 16 選

注意書き #

あらかじめ言っておくのですが、今回はそこまで実践的なことは書いていません。
というのも、Material UIの機能を紹介するにしても、できることが多すぎてどこを抜粋するか悩んでしまったためです(苦笑)

公式ドキュメントを見ていただくとよくわかると思うのですが、あらゆる使用例、サンプルコード(JS、TSともに)およびプレビュー表示が豊富に載っています。さらっと見ていくだけでも、こんなコンポーネントも用意されているのかと発見があって楽しいくらいです。

なので、提供されているコンポーネントに関しては、大まかな概要を紹介する程度にとどめます。
もし興味がわいた方はぜひ公式ドキュメントを見てみてください。
各コードにはCodeSandboxへのリンクもあるので、お気軽に試せますよ。

インストール #

一言でMaterial UIと言っても、ライブラリ的にはいくつかに分かれています。
その中で基本となるのが @material-ui/coreで、このライブラリだけでもほとんどのコンポーネントが使用できます。

$ yarn add @material-ui/core

今回の使用バージョンは4.9.10です。

その他のライブラリとしては以下のようなものがあります。必要に応じて適宜インストールしてください。

  • @material-ui/icons:SVGアイコンコンポーネント集(アイコン一覧:Material UI - Material Icons
  • @material-ui/lab:トグルボタンなど、coreにはないコンポーネント集
  • @material-ui/pickers:Date Picker的なコンポーネント集

使い方 #

以下、記載しているコードは公式ドキュメントのコードを元にしています。
画像やGIFに関しても、公式ドキュメントのプレビューが撮影元です。

基本的な使い方 #

使いたいコンポーネントをimportして使用。
独自定義のコンポーネントを使用する時とほぼ同じですが、コンポーネントによったpropsの値を設定して見た目のカスタマイズができます。

import React from 'react';
import Button from '@material-ui/core/Button';

const App = () => {
  return (
    <Button variant="contained" color="primary">
      Test
    </Button>
  );
}

export default App;

スタイルのカスタマイズ #

各コンポーネントのpropsでカスタマイズできる範囲外で、自分であてるスタイルをカスタマイズすることもできます。

CSSプロパティ名はキャメルケースで記述することに注意です。

Hooks式 #

@material-ui/core/stylesmakeStylesを使います。

定義したスタイルをclassesにいれておいて、それを各要素に割り当てていく方式です。
従来のHTML・CSSのやり方に近いですね。

import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';

const useStyles = makeStyles({
  button: {
    backgroundColor: 'green'
  }
});

const MaterialUIHooks = () => {
  const classes = useStyles();
  return (
    <Button variant="contained" className={classes.button}>
      Test
    </Button>
  );
}

export default MaterialUIHooks;

Styled Component式 #

@material-ui/core/stylesstyledを使います。

あらかじめスタイルをあてたコンポーネントを作成し、それを使用していくようなイメージです。

import React from 'react';
import { styled } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';

const CustomButton = styled(Button)({
  backgroundColor: 'red'
});

const MaterialUIStyled = () => {
  return (
    <CustomButton>Test</CustomButton>
  );
}

export default MaterialUIStyled;

HOC式(※旧式) #

@material-ui/core/styleswithStylesを使います。

withStylesでラップすることで、定義したスタイルとコンポーネントを結合。スタイルの情報はpropsのclassesに格納されるので、それを各要素に割り当てていきます。
こちらも従来のHTML・CSSのやり方に近いですね。

import React from 'react';
import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';

const styles = {
  button: {
    backgroundColor: 'orange'
  }
};

const MaterialUIHOC
= props => {
  const { classes } = props;
  return (
    <Button variant="contained" className={classes.button}>
      Test
    </Button>
  );
}

export default withStyles(styles)(MaterialUIHOC);

テーマの適用 #

全体で共通して使用するようなスタイルを、あらかじめテーマとして定義しておいて使うこともできます。

ルート階層にてThemeProviderコンポーネントでアプリのコンポーネントをラップすることで、下層のコンポーネントにテーマ情報を渡します。

import { ThemeProvider } from '@material-ui/core/styles';
.
.
.
const theme = {
  color: 'blue',
};
.
.
.
ReactDOM.render(
  <ThemeProvider theme={theme}>
    <App />
  </ThemeProvider>,
  document.getElementById('root')
);

あとは各コンポーネント側で使用できます。

import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';

const useStyles = makeStyles((theme) => ({
  button: {
    backgroundColor: theme.color
  }
}));

const MaterialUIHooks = () => {
  const classes = useStyles();
  return (
    <Button variant="contained" className={classes.button}>
      Test
    </Button>
  );
}

export default MaterialUIHooks;

※2020/05/06追記
また、createMuiThemeを使った書き方もできます。
こちらの場合はMaterial UIのデフォルトのパレットカラーを変更することも可能です。

デフォルトのパレットカラーについてはこちらを参照。

import { ThemeProvider } from '@material-ui/core/styles';
import purple from '@material-ui/core/colors/purple';
import green from '@material-ui/core/colors/green';
.
.
.
const theme = createMuiTheme({
  palette: {
    primary: purple,
    secondary: green,
  },
  status: {
    danger: 'orange',
  },
});
.
.
.
ReactDOM.render(
  <ThemeProvider theme={theme}>
    <App />
  </ThemeProvider>,
  document.getElementById('root')
);

こちらも同様に各コンポーネント側で使用できます。
primaryの元々の色は青ですが、この場合変更しているので紫になります。

import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';

const useStyles = makeStyles((theme) => ({
  button: {
    backgroundColor: theme.status.danger
  }
}));

const MaterialUIHooks = () => {
  const classes = useStyles();
  return (
    <div>
      <Button variant="contained" color="primary">primary</Button>
      <Button variant="contained" className={classes.button}>
        danger
      </Button>
    </div>
  );
}

export default MaterialUIHooks;

その他スタイルの書き方 #

このクラスの中のこの要素や、この要素のこのアクションといったような、ネストのスタイル指定はこのようになります。

import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Typography from '@material-ui/core/Typography';

const useStyles = makeStyles({
  msg: {
    color: 'blue',
    '& span': {
      color: 'red',
      '&:hover': {
        color: 'black'
      }
    }
  }
})

const MaterialUIHooks = () => {
  const classes = useStyles();
  return (
    <Typography className={classes.msg}>
      これは<span>テスト</span>です
    </Typography>
  )
}

export default MaterialUIHooks;

コンポーネント側でスタイルの値を指定する場合はuseStylesの引数に渡して、その値をスタイル定義側で使うようにします。

import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';

const useStyles = makeStyles({
  button: props => ({
    backgroundColor: props.backgroundColor
  })
})

const MaterialUIHooks = () => {
  const props = { backgroundColor: 'gray'};
  const classes = useStyles(props);
  return (
    <Button variant="contained" className={classes.button}>
      Test
    </Button>
  )
}

export default MaterialUIHooks;

コンポーネントの種類 #

大まかな種類の概要だけさらっと書きます。
なので、ここに書いているもの以外のコンポーネントもあります。
(それでも長くなりました…)

()はどのライブラリに属しているかです。

Layout #

他のコンポーネントをラップして使われる、レイアウトに関するコンポーネント集。

Box(core) #

他のコンポーネントをラップし、スタイルをあてるためのコンポーネント。デフォルトではdivとしてラップするが、他のものに指定もできる。
あてられるスタイルの種類は、公式ドキュメントのドロワーのSystem配下のページを参照。

Container(core) #

中央揃えするコンポーネント。

Grid(core) #

グリッドレイアウトを表現するためのコンポーネント。

GridList、GridListTile、GridListTileBar(core) #

画像をグリッドリストとして表現するためのコンポーネント。

Hidden(core) #

コンポーネントを非表示にするコンポーネント。ブレイクポイントを設定して、画面幅によって非表示にするなどができる。

Inputs #

フォームなどで使用する、入力に関するコンポーネント集。

Button、IconButton(core) #

ボタンコンポーネント。
Buttonはシンプルなものから、枠線あり、塗りつぶし、アイコンと組み合わせたものなど、いろんなパターンに対応。
IconButtonはアイコン自体をボタンにしたもの。

Buttonの例
Buttonコンポーネントのプレビュー画像

IconButtonの例
IconButtonコンポーネントのプレビュー画像

ButtonGroup(core) #

ボタンをグループ化したコンポーネント。

ButtonGroupの例
ButtonGroupコンポーネントのプレビュー画像

Checkbox(core) #

チェックボックスコンポーネント。FormControlLabelと組み合わせることで、ラベル付きのものも作れる。

Checkboxの例(FormControlLabelと組み合わせ)
Checkboxコンポーネントのプレビュー画像

Fab(core) #

Floating Action Buttonの略。少し浮いているようなボタンのコンポーネント。

Fabの例
Fabコンポーネントのプレビュー画像

MuiPickersUtilsProvider, KeyboardTimePicker, KeyboardDatePicker(pickers) #

Date Picker的なコンポーネント。
詳細はMaterial-UI Pickersから。

KeyboardDatePickerの例(variantにinline指定)
KeyboardDatePicker(inline)コンポーネントのプレビューGIF

KeyboardDatePickerの例(variantにdialog指定)
KeyboardDatePicker(dialog)コンポーネントのプレビューGIF

KeyboardTimePickerの例
KeyboardTimePickerコンポーネントのプレビューGIF

RadioGroup、Radio(core) #

ラジオボタンコンポーネント。FormControlLabelと組み合わせることで、ラベル付きのものも作れる。

RadioGroup、Radioの例
RadioGroup、Radioコンポーネントのプレビュー画像

Select(core) #

セレクトボックスコンポーネント。選択肢をグルーピングすることもできる。

Selectの例
SelectコンポーネントのプレビューGIF

Slider(core) #

スライダーコンポーネント。

Sliderの例
Sliderコンポーネントのプレビュー画像

Switch(core) #

スイッチコンポーネント。FormControlLabelと組み合わせることで、ラベル付きのものも作れる。

Switchの例
Switchコンポーネントのプレビュー画像

Text Field(core) #

テキスト入力フォームのコンポーネント。マルチラインにしたり、セレクトボックスにしたりもできる。また、フォームにアイコンをつけたり、単位の文字をつけるといったことも可能。

TextFieldの例
TextFieldコンポーネントのプレビュー画像

ナビゲーションに関するコンポーネント集。

BottomNavigation、BottomNavigationAction(core) #

スマホアプリでよくあるような、ボタンナビゲーションコンポーネント。

BottomNavigation、BottomNavigationActionの例
BottomNavigation、BottomNavigationActionコンポーネントのプレビュー画像

パンくずリスト的なコンポーネント。Linkと組み合わせたりする。

Breadcrumbsの例
Breadcrumbsコンポーネントのプレビュー画像

Drawer(core) #

ドロワーコンポーネント。Buttonと組み合わせて、クリックされたときにドロワーを開くといったように使う。
画面の上下左右どこからドロワーが開くか設定できる。

Drawerの例(上から開いた例)
DrawerコンポーネントのプレビューGIF

Link(core) #

リンクコンポーネント。React Routerを併用する場合は、あまり使う機会ないかも?

Linkの例
Linkコンポーネントのプレビュー画像

メニューコンポーネント。Buttonと組み合わせて、クリックされたときにメニューを開くといったように使う。

Menu、MenuItemの例(メニューを開いた後)
Menu、MenuItemコンポーネントのプレビューGIF

Stepper、StepLabel(core) #

ステッパーコンポーネント。ステップ手順を踏んでいくような表現ができる。

Stepper、StepLabelの例
Stepper、StepLabelコンポーネントのプレビュー画像

Tabs(core) #

タブコンポーネント。アイコンを使って、ボタンナビゲーションのようにすることもできる。

Tabsの例
Tabsコンポーネントのプレビュー画像

Surfaces #

表面的なUIに関するコンポーネント集。

AppBar、ToolBar(core) #

ヘッダーに使えるようなバーのコンポーネント。

AppBar、ToolBarの例
AppBar、ToolBarコンポーネントのプレビュー画像

Paper(core) #

積み重なった紙のような表現ができるコンポーネント。

Paperの例
Paperコンポーネントのプレビュー画像

Card、CardActionArea、CardActions、CardContent、CardHeader、CardMedia(core) #

カードコンポーネント。文字だけでなく画像もいれられる。

Card、CardActions、CardContent、CardHeader、CardMediaの例
Card、CardActions、CardContent、CardHeader、CardMediaコンポーネントのプレビュー画像

ExpansionPanel、ExpansionPanelActions、ExpansionPanelDetails、ExpansionPanelSummaly(core) #

ハンバーガメニューのようなコンポーネント。

ExpansionPanel、ExpansionPanelDetails、ExpansionPanelSummalyの例
ExpansionPanel、ExpansionPanelDetails、ExpansionPanelSummalyコンポーネントのプレビューGIF

Feedback #

ユーザに状態を伝えるようなコンポーネント集。

CircularProgress、LinearProgress(core) #

プログレスコンポーネント。読み込み中の表現ができる。

CircularProgressの例
CircularProgressコンポーネントのプレビューGIF

Dialog、DialogActions、DialogContent、DialogContentText、DialogTitle(core) #

ダイアログコンポーネント。Buttonと組み合わせて、クリックされたときにダイアログを開くといったように使う。

SimpleDialogの例
SimpleDialogコンポーネントのプレビューGIF

Snackbar(core) #

スナックバーコンポーネント。Buttonと組み合わせて、クリックされたときにメッセージを出すといったように使う。

Snackbarの例
SnackbarコンポーネントのプレビューGIF

Backdrop(Core) #

アプリ上の状態変化を表現できる、背景のコンポーネント。

Backdropの例(CircularProgressとの組み合わせ)
BackdropコンポーネントのプレビューGIF

Data Display #

データを表示することに関するコンポーネント集。

Avatar、AvatarGroup(core) #

アバターコンポーネント。画像や名称を指定してユーザのアイコンのような表現ができる。

Avatarの例
Avatarコンポーネントのプレビュー画像

Badge(core) #

バッジコンポーネント。アイコンなどと組み合わせて通知を表現できる。

Badgeの例
Badgeコンポーネントのプレビュー画像

Chip(core) #

チップコンポーネント。入力や属性、アクションを表現できる。

Chipの例
Chipコンポーネントのプレビュー画像

Divider(core) #

線を表現できるコンポーネント。デフォルトではhrとして変換される。

Dividerの例(線の部分)
Dividerコンポーネントのプレビュー画像

Material Icons(icons) #

アイコンのコンポーネント集。アイコンの種類は Material UI - Material Icons を参照。

List、ListItem、ListItemAvatar、ListItemIcon、ListItemSecondaryAction、ListItemText、ListSubHeader(core) #

リスト表示を表現できるコンポーネント。

List、ListItem、ListItemIcon、ListItemTextの例
List、ListItem、ListItemIcon、ListItemTextコンポーネントのプレビュー画像

Table、TableBody、TableCell、TableContainer、TableFooter、TableHead、TablePagination、TableRow、TableSortLabel(core) #

テーブル表示を表現できるコンポーネント。テーブル内のパーツごとにコンポーネントが分かれており、ソート機能も導入できる。

Table、TableBody、TableCell、TableContainer、TableHead、TableRowの例
Table、TableBody、TableCell、TableContainer、TableHead、TableRowコンポーネントのプレビュー画像

Tooltip(core) #

ツールチップコンポーネント。ラップしているコンポーネントをホバーした時に、簡易説明を表示するような表現ができる。

Tooltipの例
TooltipコンポーネントのプレビューGIF

Typography(core) #

文字表示を表現できるコンポーネント。文字位置や文字色、どのタグ(h1など)とするか、どのタグのスタイルをあてるかなどを設定できる。

Typographyの例
Typographyコンポーネントのプレビュー画像

Utils #

ユーティリティ的なコンポーネント集。

ClickAwayListener(core) #

要素の外でクリックイベントが発生したかどうかを検出するコンポーネント。

CSSBaseline、ScopedCssBaseline(core) #

normalize.cssのような、CSSをリセットするコンポーネント。ブラウザごとの表示を統一したい時に使用。

Modal(core) #

モーダルコンポーネント。Dialog、Drawer、Menu、Popoverから活用されている下位レベルの要素。

Modalの例
ModalコンポーネントのプレビューGIF

NoSsr(core) #

ラップしたコンポーネントをSSR(サーバサイドレンダリング)の対象から外すコンポーネント。
SSRの時間を短縮、SSRに対応していないコンポーネントをエスケープなどに使う。

Popover(core) #

ポップオーバーコンポーネント。コンテンツを別のコンテンツの上に表示する表現ができる。

Popoverの例
PopoverコンポーネントのプレビューGIF

Popper(core) #

ポッパーコンポーネント。これもコンテンツを別のコンテンツの上に表示する表現ができる。
上に表示されたコンテンツはスクロールについてこないなど、Popoverと微妙な違いがある。

Popperの例
PopperコンポーネントのプレビューGIF

Portal(core) #

ポータルコンポーネント。ラップしたコンポーネントを現在のDOM階層外の新しいサブツリーにレンダリングすることに使う。

TextareaAutosize #

テキストエリアコンポーネント。デフォルトでは自由にサイズを変更できるが、サイズや行数を固定することもできる。

TextareaAutosizeの例
TextareaAutosizeコンポーネントのプレビューGIF

Collapse(core) #

ラップしたコンポーネントで、上から下へ表示される表現ができるコンポーネント。

Collapseの例
CollapseコンポーネントのプレビューGIF

Fade(core) #

ラップしたコンポーネントで、フェードイン、フェードアウトを表現できるコンポーネント。

Fadeの例
FadeコンポーネントのプレビューGIF

Grow(core) #

ラップしたコンポーネントを順番にフェードインするような表現ができるコンポーネント。

Growの例
GrowコンポーネントのプレビューGIF

Slide(core) #

ラップしたコンポーネントをスライド表示する表現ができるコンポーネント。スライドする方向は指定できる。

Slideの例(derectionにup指定)
SlideコンポーネントのプレビューGIF

Zoom(core) #

ラップしたコンポーネントが、要素の中心から外側に広がるように表示する(もしくはその逆)表現ができるコンポーネント。

Zoomの例
ZoomコンポーネントのプレビューGIF

Lab #

まだcoreへは組み込まれていないコンポーネント集。

Alert、AlertTitle(lab) #

アラートコンポーネント。ユーザへ促す注意や案内を表現する。

Alertの例
Alertコンポーネントのプレビュー画像

Autocomplete(lab) #

サジェスト入力フォームを実現できるコンポーネント。複数選択式にすることも可能。

AutoCompleteの例
AutoCompleteコンポーネントのプレビューGIF

Pagination、PaginationItem(lab) #

ページネーションを表現できるコンポーネント。

Paginationの例
Paginationコンポーネントのプレビュー画像

Rating(lab) #

レーティングを表現できるコンポーネント。

Ratingの例
RatingコンポーネントのプレビューGIF

Skeleton(lab) #

コンテンツの読み込み中にスケルトンを表示するような表現ができるコンポーネント。

Skeletonの例
SketetonコンポーネントのプレビューGIF

SpeedDial、SpeedDialIcon、SpeedDialAction(lab) #

スピードダイヤルで3~6の関連アクションを表示するような表現ができるコンポーネント。

SpeedDial、SpeedDialIcon、SpeedDialActionの例
SpeedDial、SpeedDialIcon、SpeedDialActionコンポーネントのプレビューGIF

ToggleButton、ToggleButtonGroup(lab) #

トグルボタンコンポーネント。

ToggleButton、ToggleButtonGroupの例
ToggleButton、ToggleButtonGroupコンポーネントのプレビュー画像

TreeView、TreeItem(lab) #

ツリービューを表現できるコンポーネント。

TreeView、TreeItemの例
TreeView、TreeItemコンポーネントのプレビュー画像


概要だけさらっと書くつもりがすごく長くなってしまいました。
ここまで読んでくださった方、ありがとうございます!

それだけ提供している機能が多いということでもあるので、味方につけるときっと頼もしい存在になってくれると思います。
ちなみに自分が業務で使用していた時に、使用バージョンだと対応してなくて泣く泣く使うことができなかった機能もありました(笑)

この記事を書くにあたって、改めて公式ドキュメントを読んで新しい発見もあって、より使いこなせるようになりたいなと思いました。
Material UIがどんなものなのか、大まかにでも伝わっていれば幸いです。

参考リンクまとめ #

シリーズ記事 #