React with TypeScript プロジェクトに Material-UI を導入してみる
React with TypeScript のプロジェクトにて、 Material-UI を使い始めるまでの方法について書いていきます。
簡単な管理画面(ダッシュボード)を作成して完了としたいのですが、当該記事では Material-UI を利用する環境を用意して終えることにします。利用方法については次の記事に任せる構成にします。
シリーズ一覧
前提事項
事前準備
以下の記事で書きました、 React を TypeScript で利用する環境を作成済であることを前提とします。
この記事中の内容は、上記作業を終えた上で行っているモノと読んでください。
バージョン情報
今回の記事は以下のバージョンで行ったことを前提としています。バージョン違いで記事の内容と異なる場合がありますので、その点はご了承ください。
主要なライブラリは以下になります。
ライブラリ | バージョン |
---|---|
material-ui | ^4.11.2 |
react | ^17.0.1 |
react-router-dom | ^5.2.0 |
typescript | ^4.1.3 |
参考までに、今回の記事に関係ないライブラリも含めた package.json
も掲載しておきます。
// package.json { // 中略 "dependencies": { "@material-ui/core": "^4.11.2", "@material-ui/icons": "^4.11.2", "@testing-library/jest-dom": "^5.11.6", "@testing-library/react": "^11.2.2", "@testing-library/user-event": "^12.6.0", "@types/jest": "^26.0.19", "@types/node": "^12.19.11", "@types/react": "^16.14.2", "@types/react-dom": "^16.9.10", "react": "^17.0.1", "react-dom": "^17.0.1", "react-router-dom": "^5.2.0", "react-scripts": "4.0.1", "typescript": "^4.1.3", "web-vitals": "^0.2.4" }, // 中略 "devDependencies": { "@types/react-router-dom": "^5.1.7", "@typescript-eslint/eslint-plugin": "^4.11.0", "@typescript-eslint/parser": "^4.11.0", "eslint": "^7.16.0", "eslint-config-airbnb": "^18.2.1", "eslint-config-prettier": "^7.1.0", "eslint-plugin-import": "^2.22.1", "eslint-plugin-jsx-a11y": "^6.4.1", "eslint-plugin-prettier": "^3.3.0", "eslint-plugin-react": "^7.21.5", "eslint-plugin-react-hooks": "^4.2.0", "prettier": "^2.2.1" } }
Material-UI のインストール
Material-UI のインストールです。
こちらの手順にある内容をまず実施しておきます。
npm
でインストールするのは以下の2つ。
$ npm install --save @material-ui/core $ npm install --save @material-ui/icons
フォントは HTML ファイルに追加することにします。
<!-- ./public/index.html --> <!-- 前略 --> <head> <!-- 中略 --> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" /> <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" /> <!-- 中略 --> </head> <!-- 後略 -->
例えば、 Material-UI の Date Picker のような部品を利用したいとなったなら @material-ui/pickers
もインストールする必要があります。こういった部品(Button や DatePicker など)に関しては公式サイトに解説のページがあります。そしてそのページ内で追加でインストールすべきモノが説明されています。ですので、今後部品が必要になった都度インストールすればOKかと思います。
ということで、今回は一旦ここまで。あとは必要に応じて。
簡単な画面の作成(Material-UI 利用前)
続いて、簡単な画面を作成することにします。
今回はめっちゃ簡素なダッシュボードのようなものを作ります。「Top ページ」と「About ページ」いう2ページのみの構成とし、互いに行き来ができるようにします。ダッシュボードという名の「テンプレート」を用意し、「Top ページ」と「About ページ」は、この「テンプレート」の中に表示されるようにします。
ディレクトリ・ファイル構成
「テンプレート」と「Top ページ」と「About ページ」に対応したファイルを追加します。ディレクトリ構成は好みが分かれるところでしょうが、取り敢えず今回は下記のような形にします。
./src │ App.css │ App.test.tsx │ App.tsx │ index.css │ index.tsx │ logo.svg │ react-app-env.d.ts │ reportWebVitals.ts │ setupTests.ts │ ├─assets ### <-ADD 画像などの静的ファイルを入れる。 ├─components ### <-ADD 部品置き場。<HogeButton /> みたいな独自タグを作っていく。 ├─consts ### <-ADD 定数置き場。 ├─pages ### <-ADD 画面置き場。 │ AboutPage.tsx ### <-ADD About ページ │ TopPage.tsx ### <-ADD Top ページ │ └─templates ### <-ADD テンプレート置き場。 DashboardTemplate.tsx ### <-ADD ダッシュボードのテンプレート
ということで、ディレクトリとファイルを追加します。
$ mkdir src/assets $ mkdir src/components $ mkdir src/consts $ mkdir src/pages $ mkdir src/templates $ touch src/pages AboutPage.tsx $ touch src/pages TopPage.tsx $ touch src/templates DashboardTemplate.tsx
ページの作成
「Top ページ」と「About ページ」を作ります。最初は超単純にしておきましょう。
// /src/pages/TopPage.tsx import React from 'react'; const TopPage: React.FC = () => { return <>トップページの内容</>; }; export default TopPage;
// /src/pages/AboutPage.tsx import React from 'react'; const AboutPage: React.FC = () => { return <>アバウトページの内容</>; }; export default AboutPage;
ルーティング
次に、作成したページを表示させるためのルーティングを作っていきます。
ページを遷移させるルーティングの機能には react-router-dom
を利用します。 TypeScript を使っていますので、型もインストールします。型は開発環境でしか使いませんので --save-dev
オプションにしています。
$ npm install --save react-router-dom $ npm install --save-dev @types/react-router-dom
src/App.tsx
がアプリケーションの入り口になります。ここにルーティングを書くことになります。以下のように編集します。
// src/App.tsx import React from 'react'; import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; import AboutPage from './pages/AboutPage'; import TopPage from './pages/TopPage'; const App: React.FC = () => { return ( <Router> <Switch> <Route path="/" component={TopPage} exact /> <Route path="/about" component={AboutPage} exact /> </Switch> </Router> ); }; export default App;
これで、 http://localhost:3000/
は「Top ページ」へ、 http://localhost:3000/about
は「About ページ」に遷移します。
ページ遷移の <a>
タグの設置には <Link>
を使います。<Link to="/about">About</Link>
のように書くと、 AboutPage
へのリンクが設置されます。
今回はルーティングが本題ではありませんので、解説は省きます。ただ、今回は公式サイトの「Quick Start」に書かれているレベルのことしかしていませんので、知りたい方は下記を見ていただければいいかな、と。
テンプレートの作成
次に、「テンプレート」を作ってみましょう。まずは簡単な構成にします。
// /src/templates/DashboardTemplate.tsx import React from 'react'; export interface DashboardTemplateProps { children: React.ReactNode; title: string; } const DashboardTemplate: React.FC<DashboardTemplateProps> = ({ children, title, }) => { return ( <div> <h1>{title}</h1> <div>{children}</div> </div> ); }; export default DashboardTemplate;
呼び出し元には title
という属性を指定してもらいます。これを h1
で表示します。
呼び出し元の内容は、 children
になります。ここは取り敢えず div
で囲って表示します。( <>
でもいいのかもしれません。ですが、確実にブロックレベルになるように div
っていた方がトラブらないかな? と思ってこうしてます。)
「呼び出し元ではどう使うんだ?」というのが分からないとピンと来ないとは思いますので、この辺りは後述します。
title
と children
は DashboardTemplate
のプロパティ(props
)となりますので、 DashboardTemplateProps
という interface
を作りました。これを DashboardTemplate: React.FC<DashboardTemplateProps>
のように型指定します。
テンプレートの利用
それでは作成した「テンプレート」を「Top ページ」と「About ページ」で利用してみましょう。
// /src/pages/TopPage.tsx import React from 'react'; import DashboardTemplate from '../templates/DashboardTemplate'; // <=ADD const TopPage: React.FC = () => { // DashboardTemplate で囲うよう変更 return ( <DashboardTemplate title="トップページのタイトル"> <>トップページの内容</> </DashboardTemplate> ); }; export default TopPage;
// /src/pages/AboutPage.tsx import React from 'react'; import DashboardTemplate from '../templates/DashboardTemplate'; // <=ADD const AboutPage: React.FC = () => { // DashboardTemplate で囲うよう変更 return ( <DashboardTemplate title="アバウトページのタイトル"> <>アバウトページの内容</> </DashboardTemplate> ); }; export default AboutPage;
DashboardTemplate
タグで囲うように変更しました。
DashboardTemplate
タグには title="トップページのタイトル"
という属性を記述しています。これが <h1>{title}</h1>
の {title}
として使われます。
DashboardTemplate
タグの中身の <>アバウトページの内容</>
が <div>{children}</div>
の {children}
として使われます。
結果として、以下のような HTML として出力されます。( <>...</>
は React の便宜上書いている意味無しタグなので、HTML出力時には無視されます。)
<div> <h1>トップページのタイトル</h1> <div>トップページの内容</div> </div>
ということで、 Chrome に表示されたイメージと、出力されたHTMLは以下の画像のようになりました。
Material-UI の簡単な利用
ここまでで Material-UI を利用するための土台ができあがりました。次は「テンプレート」で Material-UI のコンポーネントを利用してみたいと思います。
今回は「テンプレート」の変更を行います。画面上部のヘッダーとして AppBar
を追加し、そこに2つのページに遷移するリンクを設置します。
ヘッダーの追加
/src/templates/DashboardTemplate.tsx
を変更します。内容の全貌は以下の通りです。
// /src/templates/DashboardTemplate.tsx import React from 'react'; // 以下の import を追加 import { Link } from 'react-router-dom'; import AppBar from '@material-ui/core/AppBar'; import Toolbar from '@material-ui/core/Toolbar'; import Container from '@material-ui/core/Container'; export interface DashboardTemplateProps { children: React.ReactNode; title: string; } const DashboardTemplate: React.FC<DashboardTemplateProps> = ({ children, title, }) => { return ( <div> {/* (1) <AppBar>...</AppBar> を追加 */} <AppBar> <Toolbar> <nav> <Link to="/">Top</Link> <Link to="/about">About</Link> </nav> </Toolbar> </AppBar> {/* (2) <div> を <Container> に変更 */} <Container> <h1>{title}</h1> <div>{children}</div> </Container> </div> ); }; export default DashboardTemplate;
(1) AppBar の追加と Container への変更
{/* (1) <AppBar>...</AppBar> を追加 */}
にある AppBar
の追加についてです。
{/* (1) <AppBar>...</AppBar> を追加 */} <AppBar> <Toolbar> <nav> <Link to="/">Top</Link> <Link to="/about">About</Link> </nav> </Toolbar> </AppBar>
AppBar
はヘッダーを作るモノ、 Toolbar
はその中で要素を横に並べるモノになります。組み合わせて利用します。(※1)
ナビゲーションのリンクなので一応 <nav>
を書いて、その中に <Link>
タグでリンク(<a>
として出力される)を配置しました。
AppBar についての Material-UI の公式サイトは下記になります。
※1. AppBar
と Toolbar
の違いはなんじゃろと思ってましたが、同じ疑問が下記にて解消されていました。
(2) Container への変更
続いて、 {/* (2) <div> を <Container> に変更 */}
にある Container
の利用についてです。
{/* (2) <div> を <Container> に変更 */} <Container> <h1>{title}</h1> <div>{children}</div> </Container>
これは div
を Container
に変更しただけです。 Container
は中央寄せされる div
というくらいに思ってください。
これで以下のように表示されます。
Top と About のリンクで画面がカチカチ切り替わります。 <h1>
の部分が隠れちゃったのと、リンク部分がちょっと窮屈なので、その点の改善を少しやっていきたいと思います。
が! 流石に長くなりそうなので次の記事にて話を続けます。