JavaScript
Facebook
react.js
React
material-ui

create-react-appで作成したReact+Material-UI開発環境のメモ

概要

create-react-appで作成したReact+Material-UI開発環境、を昨日から使い始めました!いろいろ詰まると思うので、それぞれメモっておきたいとおもいます。

とりあえず公開しておきますが、今後も随時追加していく予定です。

開発環境のつくりかた

まずは以下の2つのツールを使えるようにしておいて

npm install -g create-react-app
npm install -g serve

例えば react-test という開発環境を作成するとすると、以下を順に実行します。

create-react-app react-test
cd react-test
npm install material-ui --save
npm start

これでブラウザが起動してサンプルページが表示されますので、あとは src/App.js を修正するだけ!

完成したら以下を実行してブラウザで表示を確認し、問題なければ build フォルダをWebサーバーなどにアップロード&公開して完了。

npm run build
serve -s build

詳しい経緯は React開発環境のセットアップで挫折し、create-react-appに救われた件 を参考にしてみてください。

テーマエラーが表示されてしまう

以下のように Material-UI のパーツを <MuiThemeProvider> タグで囲んでください。

<MuiThemeProvider>
  <Chip onRequestDelete = {() => alert("delete")}>
    Chip test
  </Chip>
</MuiThemeProvider>

アイコンが表示されない

JSX で以下のようにタブなどにアイコンを設定しても

  <Tabs>
  <Tab
    icon={<FontIcon className="material-icons">home</FontIcon>}
    label="HOME"
  >

以下のようにアイコンではなく文字で表示されてしまう場合、

image.png

Google が提供しているフォントアイコン用の以下のCSSが読み込まれていないのが原因のようです。なのでこのファイルをローカルに保存し、

<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">

以下のように import してあげればokです。

import './MaterialIcons.css';

image.png

なおアイコンを探す場合は Material icons - Material Design からどうぞ。

リストの値を覚えてくれない

値をひとつ選択できる SelectField ですが、最初、以下のように簡単に書いたら値を覚えてくれませんでした。選択しても空のままです。

<SelectField floatingLabelText="List selection">
  <MenuItem value={1} primaryText="categoiry1" />
  <MenuItem value={2} primaryText="categoiry2" />
  <MenuItem value={3} primaryText="categoiry3" />
</SelectField>

状態を覚えさせるためには、公式サイトのサンプルのように、クラス化する必要がありそうです。でも数多くある場合、いちいちクラス化するのも面倒ですよね?

とりあえず以下のように記述したら値を覚えてくれました。

<SelectField floatingLabelText="List selection"
  value={this.state ? this.state.value : 1}
  onChange={(event, index, values) => this.setState({value:values})}
>
  <MenuItem value={1} primaryText="categoiry1" />
  <MenuItem value={2} primaryText="categoiry2" />
  <MenuItem value={3} primaryText="categoiry3" />
</SelectField>

クラス化しないと SelectField 内の state を初期化できない、なので最初に value 属性をセットする際に undefined エラーになる、のが問題のようでした。

そこでちょっと強引ですが、value 属性の式に、state が未定義の場合には初期値(今回は1)を渡すように処理を加えてみました。ちなみに onChange 式のほうは公式のクラス化するコードと同じです。

で、うまく動作するようにみえましたが… これは駄目でした。2個目の SelectField を追加すると、両者で値が連動してしまいます。つまり、state を共有してしまうようで、クラス変数になっちゃってる?感じの動きです。

なので上記のサンプルをちょっと修正した以下を利用しました。まず値を保持するために専用の変数を用意して、初期値をセットしておきます。

var sf_value1 = 1;

後は処理を以下のように書き換えればok。

<SelectField floatingLabelText="List selection"
  value={sf_value1}
  onChange={(event, index, values) => {sf_value1 = values; this.setState({value:values})}}
>

かなりベタな感じになりましたが、それぞれ別々のクラスを定義するよりはマシかと。

ただしこの方法だと、たぶん this.setState() でこの方法で実装した全てのSelectField に更新イベントが飛ぶとおもわれます。あまりに数が多かったり、リストの動的作成などで処理が重いものがあれば、ちゃんとクラス化したほうが良いとおもわれます。

こんど余裕があったら、複数あっても連動しない、簡単に使えるリスト部品が作れないか考えてみたいとおもいます。

Node.js サーバーと通信できない

自作の Node.js アプリのフロント部分を React+Material-UI で書き直してみたのですが、アプリAPIへのアクセスが動作しなくて困りました。

自身の Node.js アプリは //localhost:6001/api/* でサービスを受けつけているのですが、create-react-app でプレビュー中のページは //localhost:3000/ なので、CORS(Cross-Origin Resource Sharing) 問題が発生してアクセスできません。ビルドして Node.js アプリ側に反映すれば動作しますが、時間がかかり面倒です。

たぶん create-react-app でプレビュー用に動作しているwebサーバーのヘッダに Access-Control-Allow-Origin: を設定すれば良いのですが、いまいちどう動作しているかわからず…

とりあえず現在は Chrome Extension の CORS で無理やりアクセスを許可させて動作確認しています。こんな感じで…

image.png

おわりに

React + Material-UI を使い始めて2日ですが、開発環境さえ作ってしまえば、わりと使いやすく、かつ洗練されたUIで良いとオモイマス。既に手元のアプリを1つ、この環境に移植中…

ただReact、というか Facebookのライセンス問題 (Facebook社と特許で係争中の会社はコードを利用できない、的な)を知って、大手のプロジェクトでは利用できない可能性が高いな、とちょっと意欲が減退気味。どうしようかな…

【追記】MITライセンスになるようで、よかった!

ではまた!