概要
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"
>
以下のようにアイコンではなく文字で表示されてしまう場合、
Google が提供しているフォントアイコン用の以下のCSSが読み込まれていないのが原因のようです。なのでこのファイルをローカルに保存し、
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
以下のように import してあげればokです。
import './MaterialIcons.css';
なおアイコンを探す場合は 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 で無理やりアクセスを許可させて動作確認しています。こんな感じで…
おわりに
React + Material-UI を使い始めて2日ですが、開発環境さえ作ってしまえば、わりと使いやすく、かつ洗練されたUIで良いとオモイマス。既に手元のアプリを1つ、この環境に移植中…
ただReact、というか Facebookのライセンス問題 (Facebook社と特許で係争中の会社はコードを利用できない、的な)を知って、大手のプロジェクトでは利用できない可能性が高いな、とちょっと意欲が減退気味。どうしようかな…
【追記】MITライセンスになるようで、よかった!
ではまた!