概要
これまでUIにはPC用でも jQuery Mobile を利用していたのですが、最近はあまり更新されていないようで、将来がちょっと不安。
そこで前から興味のあった React を試してみることにしました。最初は調子よかったのですが… 途中から環境設定の泥沼にハマり、最後は create-react-app に落ち着くまでを簡単にまとめてみました。
同じ苦労をした方であれば、共感をもって読んでもらえるかも、と期待しております。
Reactを普通に使ってみる
まずはいつも通り、jQuery なんかと同じ感覚でJSファイルを読み込み、h1要素を追加してみた。以下のようなhtmlを作成してブラウザで表示。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>React sample 1</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react-dom.min.js"></script>
</head>
<body>
<div id="root"></div>
<script>
ReactDOM.render(
React.createElement('h1', null, 'Hello, React world!'),
document.getElementById('root')
);
</script>
</body>
</html>
うん、普通に表示される。特に癖もなく使い易いライブラリな印象。
JSX表記を試してみる
このままだと jQuery との差がわからないので、JavaScriptにXML(xhtml)表記が混在するJSXとやらを試してみた。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>React sample 1</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react-dom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.24/browser.js"></script>
<script type="text/babel">
ReactDOM.render(
<h1>Hello, React world!</h1>,
document.getElementById('root')
);
</script>
</head>
<body>
<div id="root"></div>
</body>
</html>
JavaScriptにいきなりXML表記のタグが混じっています。ちょっと見慣れない表記ですが、シンプルに書けて良いですね。
ただここで、Babel の browser.js がさっと見つからず、ちょっと迷いました。最新版のパッケージには含まれていないらしく、少し古いバージョンを探して利用。
よっしゃいけた!
ここで安心して React を理解した気になっていたのですが、ここで既に罠にハマっていたのです。browser.js がなぜ廃止され、最新のパッケージからは削除されているのか、その意味をよーく考えてみるべきでした。
ちょっとだけ、イヤーな予感はしてたんですよ、ええ。
Material-UIを試してみる
React だけだとUIパーツは自分で作成する必要がありそうなので、Material-UI もあわせて試してみます。
material-ui モジュールを導入し、まず、さきほどのサンプルに1行加えてみます。
import Avatar from 'material-ui/Avatar';
と、Uncaught ReferenceError: require is not defined というエラーが発生して止まってしまいました。ブラウザ表示もされません。
require なんて使ってたっけ?たぶん Babel が import文を変換したんだろうな… と思いましたが、ここで困りました。そもそもブラウザ環境のJavaScriptに require なんて実装されていましたっけ?
ここから泥沼にハマりこみます。
悪あがき
ブラウザには importもrequreもない、あるのは <script> タグだ!と強引に Material-UI のパーツ用JSを読み込ませてみます。
exports と require() が無い!と怒られるので、ダミー定義までしてしまいます。ええ、もうヤケです。
<script>
var exports = {};
function require() {
console.log("require: " + JSON.stringify(arguments));
}
</script>
<script src="js/Avatar.js"></script>
結果、以下のようなコンソール表示とエラーになりました。
そうか、内部でいろいろ呼んでいるのね、って感じ。これらを全部 <script> で読み込んでおけば動くのかもしれませんが… ちょっと試したいだけなのにその苦労はちょっと…
ここでやっと、React はJSファイルを数個読み込めば使えるような、お手軽なライブラリではないんだ、と気がつきました。Webpackだかなんだか、ビルド環境を構築しておいて、事前にビルドするタイプのマジなやつやん、ってことに…
そして泥沼
さーどうしましょ、と半日ほど迷走しまして。
- 諦めてjQuery Mobileに戻ろうか
=> Mobileが更新されておらず最新のjQueryでエラーが発生
- ちゃんとビルド環境を構築しようか
=> Babel/Webpack関連の情報が多すぎて調べているうちに寝てしまう
- 動いてる環境を参照して無茶を継続
=> 各種ビルドスクリプトが複雑で、読んでるうちにやはり寝てしまう
結局、諦めて寝てしまいました…
create-react-app
そして翌日、ググって見つけたのが コマンド一発でReactの開発環境を構築してくれるFacebook製ツール「create-react-app」 の記事。
React の本家が作成したツールということで、さっそく導入してみました。create-react-app react-sample でプロジェクトを作成。
ファイルのダウンロードがしばらく続き、以下のような親切なメッセージが表示されて完了します。
メッセージに従って npm start を実行すると、ブラウザが自動起動して、
メッセージに従って src/App.js に数行加えてみると…
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class App extends Component {
render() {
return (
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h2>Welcome to React</h2>
</div>
<p className="App-intro">
To get started, edit <code>src/App.js</code> and save to reload.
</p>
<p className="App-body">
Yes, my mother.
</p>
</div>
);
}
}
export default App;
ファイルをセーブしただけでWebページが更新された!うーむ、昨日の苦労が嘘のようだ。楽園はここにあったのか…
Material-UIに再挑戦
この流れならば、いけるかもしれません。react-test フォルダで npm install material-ui --save とタイプし、モジュールを導入します。
ちょっと警告は出たものの導入できたっぽいので、公式ページの Chipサンプル を参考にして、独自追加部分を以下に変更。
<div style={this.styles.wrapper}>
<Chip>Chip test</Chip>
</div>
これでセーブしたところ、ちゃんとエラーが発生してひと安心。
コードにimport文を追加して、再度トライ!
import Chip from 'material-ui/Chip';
コンパイルは成功!しかし画面にはエラーが。しかもやたら見易くてわかりやすい表示で。
他にもテーマ関係のエラーが出ていたので、デフォルトのテーマらしきものを読み込み、
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
htmlの追加部分を以下のように修正。
<MuiThemeProvider>
<Chip>Chip test</Chip>
</MuiThemeProvider>
これでようやく!Material-UIのパーツが表示されました。
更に削除用のコールバック(アラート出すだけ)を追加し、最終的なテストページは以下になりました。
import React, { Component } from 'react';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import Chip from 'material-ui/Chip';
import logo from './logo.svg';
import './App.css';
class App extends Component {
render() {
return (
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h2>Welcome to React</h2>
</div>
<p className="App-intro">
To get started, edit <code>src/App.js</code> and save to reload.
</p>
<MuiThemeProvider>
<Chip
onRequestDelete = {() => alert("delete")}
>Chip test</Chip>
</MuiThemeProvider>
</div>
);
}
}
export default App;
ビルドアップ!バンバンババン!
鋼鉄ジーグ、古いですね。
さて、npm start すると表示される npm run build を試してみましょう。実行すると以下のように表示されました。
build というフォルダが自動生成されて、公開に必要そうなファイルがまとめられています。
またまた親切なアドバイスが表示されたので、簡易Webサーバー的なコマンド serve を使用してみましょう。
無事に起動できたようなので、ブラウザで確認します。
おお、良いカンジです。この環境で開発を進め、完成したら npm run build して、build フォルダ以下を公開すればok、と。なるほど良くできてます!
まとめ
今回得られた結果はこちら。
- 新しいものに挑戦する際、ちゃんと初心に戻って整備された道を進むべし
- 偉大な先駆者たちの好意に甘えるべし
そして悔しまぎれの言い訳がこちら。
- 道を踏み外したから有難味がよくわかった
- なんとなくだが内部の動きがみえた気もする
ではまた!