material-uiによる検索モード搭載のAppBarの実装
はじめに
REQLYではGoogleの提唱するマテリアルデザインに基づいた実装が行われています。material-uiは、マテリアルデザインを構成するUIパーツのReactライブラリであり、REQLYではスマホ版のAppBarなどの実装に取り入れられています。material-uiの1つ1つのコンポーネントの使い方は、公式のDemoページにサンプルコードと共に丁寧に書かれていますが、どのようにして複数のコンポーネントを組み合わせて実用的なデザインを組み上げていくのか、という実践的な内容についての情報は多くありません。今回は、REQLYのAppBarを例にmaterial-uiの実践的な使い方をしっかり説明していきたいと思います。
完成品
Dockerによって再現可能なコードをGitHub - ReqlyTokyo/appbarにて公開しています。
実装詳細
1. DockerによるReact開発環境の作成
まずは、Dockerを用いて逐次実行可能なポータブルなReact環境を作成するところから始めよう。facebookが公開しているcreate-react-appというコマンドを使えば、開発のベースとなるReactアプリケーションを簡単に作成することができる。create-react-appコマンドのインストール方法は公式ページを参照されたい。
create-react-app myapp cd myapp npm start
これによりhttp://localhost:3000/
にデフォルトページが立ち上がるはずだ。
次にこのアプリケーションをDockerfileとdocker-compose.ymlを使ってコンテナ化しよう。
Dockerfile
FROM node:9 WORKDIR /myapp COPY ./myapp/package.json . RUN npm install CMD ["npm", "start"]
./myapp/package.json
はReactプロジェクトに必要なライブラリの依存関係等が記述されたファイルで、npm install
をRUN命令で実行することで、必要なライブラリがインストールされたDockerイメージを作成できる。
docker-compose.yml
myapp: build: . ports: - "3000:3000" volumes: - ./myapp/src:/myapp/src - ./myapp/public:/myapp/public
3000番ポートの公開のほか、volumes命令によって./myapp/src
と./myapp/public
をそれぞれマウントしている。これにより、Dockerコンテナを立ち上げた状態でホスト側で./myapp/src
や./myapp/public
以下のファイルを編集したときに、リアルタイムで更新が走るようにできる。
2. material-uiによる必要なUIコンポーネントの実装
material-uiの導入
./myapp/package.json
に新たに@material-ui/core - npmと@material-ui/icons - npmへの依存関係を定義する。coreだけでなくiconsも使えば、マテリアルデザインの公式アイコン集を簡単に実装に組み込むことが可能になる。
"dependencies": { "@material-ui/core": "^1.2.0", "@material-ui/icons": "^1.1.0", "react": "^16.4.1", "react-dom": "^16.4.1", "react-scripts": "1.1.4" }
上の2行をdependenciesに追記した状態でdocker-compose build
を実行すれば、無事に必要なライブラリが揃ったDockerイメージが作られる。
次に通常モードと検索モードを表現するクラスをそれぞれ独立に実装していこう。
通常モードの実装(appbar/DefaultBar.js at master · ReqlyTokyo/appbar · GitHub)
イメージに非常に近いものがDemoページの3番目に既に実装されている。MenuIconを廃止し、SearchIconを新たに導入すれば、ほとんどイメージに近いものが得られる。この段階ではSearchIconにonClickが定義されていないので遷移自体は起こらないが、マテリアルデザインに基づいたクリック時のエフェクトなどが既に自動的に付与されていることが分かるだろう。
検索モードの実装(appbar/SearchBar.js at master · ReqlyTokyo/appbar · GitHub)
検索ウィンドウ自体はmaterial-uiに実装されていないが、material-uiを用いて実装された検索ウィンドウがMITライセンスで公開されている。これについても、一番左にBackIconを追加するだけで、ほぼイメージ通りの検索バーを実装することができる。
3. AppBarの出し分けの実装
Default.jsとSearchBar.jsが定義されたので、あとはこの2つを出し分ける親クラス(ReqlyAppBar.js)を実装すれば目的は達成できる。
親クラスの実装(appbar/ReqlyAppBar.js at master · ReqlyTokyo/appbar · GitHub)
class ReqlyAppBar extends React.Component{ state = { search: false, }; handleChange = event => { console.log("handleChange called!"); this.setState({ ['search']: !this.state.search }); }; render () { if (this.state.search) { return ( <SearchBar onChange={() => console.log('onChange')} onRequestSearch={() => console.log('onRequestSearch')} onHandleChange={this.handleChange} /> ); } else { return ( <DefaultBar onHandleChange={this.handleChange} /> ); } } } export default ReqlyAppBar;
ReqlyAppBarは、searchというbooleanのstateを持ち、それがTrueだった場合は検索モード、Falseだった場合は通常モードを描画するクラスだ。searchを反転させる関数であるhandleChangeをコールバック関数としてSearchBar, DefaultBarの呼び出し時に渡していることが分かるだろう。あとは、検索アイコンまたは戻るボタンがクリックされた場合に、このコールバック関数を発火するようにすれば、ReqlyAppBarクラスのstateが変更されてReqlyAppBarが再描画され、2つのモードが切り替わることとなる。クリック時の発火はそれぞれのIconButtonのonClickパラメタにて登録できる。
SearchBar.js
<IconButton onClick={this.props.onHandleChange} > <BackIcon /> </IconButton>
DefaultBar.js
<IconButton onClick={this.props.onHandleChange} > <Search /> </IconButton>
以上により、サーチモードに切り替え可能なAppBarが無事実装できた。
おわりに
REQLYではAppBarの他にもレシピカードなどにmaterial-uiが使用されています。是非使ってみてください! reqly.tokyo