CodeZine(コードジン)

特集ページ一覧

綺麗なコンポーネントを容易に導入できるMaterial-UIを紹介【前編】

現場で役立つ! React向けライブラリ詳説 第4回

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2021/06/14 11:00
目次

テーマを設定する

 続いて、テーマの設定方法を解説します。前述の通り、Material Designはテーマカラーを設定することでオリジナリティのあるデザインを生み出すことができます。試しに、CodeZineのカラーリングを参考にして、テーマを作ってみましょう。

 Material Designの色システムでは、19種類のベースカラーが用意されており、それの濃淡を数値で表現します。探してみると、CodeZineのメインカラーと近いのはLightBlueの800番、アクセントカラーと近いのはTealの200番でした(図7)。

図7:CodeZineの色合いに近いものを選んだ
図7:CodeZineの色合いに近いものを選んだ

 それでは、これをテーマの形に落とし込んでみましょう。リスト3はテーマを適用する実装です。

[リスト3]テーマを適用する
import { ThemeProvider, createMuiTheme } from '@material-ui/core/styles';
import lightBlue from '@material-ui/core/colors/lightBlue';
import teal from '@material-ui/core/colors/teal';
import AppBar from '@material-ui/core/AppBar';
import Button from '@material-ui/core/Button';
import Container from '@material-ui/core/Container';
import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography';

const theme = createMuiTheme({ // (1)
  palette: {
    primary: {
      main: lightBlue[800], // (3)
    },
    secondary: {
      main: teal[200], // (4)
    }
  },
});

function App() {
  return (
    <ThemeProvider theme={theme}>{/* (2) */}
      <AppBar position="static" color="primary">{/* (5) */}
        <Toolbar>
          <Typography variant="h6">サンプル</Typography>
        </Toolbar>
      </AppBar>
      <Container>
        <Button variant="contained" color="secondary">{/* (6) */}
          Hello World
        </Button>
      </Container>
    </ThemeProvider>
  );
}

export default App;

 テーマは(1)のようにcreateMuiTheme関数で作成します。作成したtheme変数を(2)のように<ThemeProvider>コンポーネントに渡して、他のMaterial-UIのコンポーネントを包むことで、テーマを適用します。色は(3)と(4)のように設定しています。

 今回は(5)で<AppBar>(ヘッダー)を使ってみました(後編で解説します)。こちらは色をprimaryに設定したので、`lightBlue[800]の色になります。また、ボタンの色はsecondaryに設定したので、teal[200]^^の色になります。それでは実際にどうなったか見てみましょう(図8)。

図8:ヘッダーとボタンがテーマの色になった
図8:ヘッダーとボタンがテーマの色になった

 それらしい色になりました。このように、テーマで色を指定することで、統一感のあるUIを容易に構築できます。

Boxの例

 それでは、もう少し実例を見てみましょう。Boxコンポーネントで領域を区切って、簡単なレイアウトを組んでみます(リスト4)。

[リスト4]Boxの例
// 略
import Box from '@material-ui/core/Box';

function App() {
  return (
    {/* (略) */}
      <Container>
        <Box style={{ display: 'flex', flexDirection: 'row' }}>{/* (1) */}
          <Box width={1/4} style={{ padding: '8px' }} border={1}>{/* (2) */}
            <Button
              variant="contained"
              color="secondary"
              style={{ width: '100%' }}
            >
              ボタン1
            </Button>
          </Box>
          <Box width={1/2} style={{ padding: '8px' }} border={1}>{/* (3) */}
            <Button
              variant="contained"
              color="secondary"
              style={{ width: '100%' }}
            >
              ボタン2
            </Button>
          </Box>
          <Box width={1/4} style={{ padding: '8px' }} border={1}>{/* (2) */}
            <Button
              variant="contained"
              color="secondary"
              style={{ width: '100%' }}
            >
              ボタン3
            </Button>
          </Box>
        </Box>
      </Container>
    {/* (略) */}
  );
}

export default App;

 まずは(1)で横方向のFlexboxを定義します。そして、 widthの値を1/4にした(2)と、1/2にした(3)を並べてみました。直感的には1:2:1の比になりそうな指定ですね。実際に動かしてみると、表示は図9のようになります。

図9:1:2:1になった
図9:1:2:1になった

 1:2:1の比になりました。Boxをはじめとしたレイアウトに関するコンポーネントでは、widthやheightに割合を指定でき、親(ここでは(1)のBox)の幅に対して割合に応じた幅を持つことができます。

Menuの例

 最後に、ナビゲーションのジャンルから、Menuコンポーネントの例を挙げてみます。ボタンを押すとメニューが開いて、選択すると閉じる、という簡単なものです(リスト5)。

[リスト5]Menuの例
function MenuSample() {
  const [anchorEl, setAnchorEl] = useState(null);

  const handleClick = (event) => {
    setAnchorEl(event.currentTarget); // (4)
  };

  const handleClose = () => {
    setAnchorEl(null); // (5)
  };

  return (
    <Box>
      <Button
        variant="contained"
        color="secondary"
        onClick={handleClick}
      >
        メニューを開く
      </Button>
      <Menu // (2)
        id="simple-menu"
        anchorEl={anchorEl} // (1)
        open={Boolean(anchorEl)} // (3)
        onClose={handleClose}
      >
        <MenuItem onClick={handleClose}>アイテム1</MenuItem>
        <MenuItem onClick={handleClose}>アイテム2</MenuItem>
        <MenuItem onClick={handleClose}>アイテム3</MenuItem>
      </Menu>
    </Box>
  );
}

 Menuコンポーネントの表示位置は(1)でanchorEl属性に設定したDOM要素からの相対位置で決定されます。そのため、JSX内ではどこに記述しても構いませんが、管理上の扱いやすさから、anchorElに設定する要素から近い場所に記述する慣例があります。今回の例では、(2)のようにButtonの真下に記述しました。

 (3)のopen属性にtrueを与えると、メニューが表示されます。ボタンのクリック時に(4)のように取得した要素を、(3)で真偽値に変換してからopen属性に渡すことで「ボタンクリックでメニューを表示」という挙動を実現しています。逆に閉じるときは、MenuItemやメニュー外をクリックした際に呼び出されるhandleClose関数内で(5)の処理をすることで、(3)に渡る値をfalseにしています。なお、開閉状態の管理と要素の管理は別々に行っても問題ありません。

まとめ

 今回はMaterial-UIの解説の前編でした。Webサイトやアプリを組み上げていくために必要な部品が初めからそろっている中で開発するのは楽しいですね。次回は引き続き、Material-UIについて解説します。



  • LINEで送る
  • このエントリーをはてなブックマークに追加

バックナンバー

連載:現場で役立つ! React向けライブラリ詳説

著者プロフィール

  • WINGSプロジェクト 中川幸哉(ナカガワユキヤ)

    <WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂...

  • 山田 祥寛(ヤマダ ヨシヒロ)

    静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for ASP/ASP.NET。執筆コミュニティ「WINGSプロジェクト」代表。 主な著書に「入門シリーズ(サーバサイドAjax/XM...

あなたにオススメ

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5