こんにちは制作担当の奥田です。
2016年冬アニメ圧倒的イチオシは「僕だけがいない街」です。
前期の「すべてがFになる」もそうでしたが、ノイタミナ枠は毎回面白いですね。
あと面白いのは「Dimension W」ですね。気になる方はぜひご覧ください。
と、アニメの話はさておき(冒頭がアニメの話ばっかりですねw)
最近はJavaScript界隈がとても活発ですね。
今回は現在人気沸騰中のライブラリ「React.js」をさわってみました。
まだまだ僕も触り始めたばかりなので超入門編といったところでしょうか。
Table of contents
React.jsとは
React.jsとはFacebookが作ったライブラリで、MVCフレームワーク(Model,View,Controller)のViewの部分をComponentとして作っていくライブラリです。
もちろん素のJavascriptでも書けるのですが、JSXというXML形式で書ける言語を使用するパターンが主流です。
JSX は、DeNAによって開発されたウェブアプリケーション向けのプログラミング言語である。 ECMAScript 4から影響を受けた構文を持ち、静的型付けなのが特徴。 ウェブブラウザ組み込みのスクリプト言語であるJavaScriptのデメリットを解消することを目的に作られている。
2017.07.25 訂正いたしました。
Reactで使うJSXは正しくはFacebook製のライブラリだそうです。
http://facebook.github.io/jsx/
gulpで環境を構築する
まずは環境の構築です。公式ではCDNを使った方法も書いてあるんですが、npmとしてインストールしておくとBrowserify(JavaScriptをrequireできる)やBabel(jsxをJavaScriptにしたりES6をES5へトランスパイルしてくれる)などのNodeモジュールと一緒に使えるので便利です。
React.js
Node.jsやgulpが入っていないという方はこの辺をご覧ください。
Gulp.js入門 – コーディングを10倍速くする環境を作る方法まとめ
まずは作業ディレクトリへ移動します。(ない方は作りましょう。)
#ない方は$ mkdir ~/workspace $ cd ~/workspace
では必要なパッケージをインストールします。
$ npm install --save-dev react react-dom browserify babelify vinyl-source-stream gulp-plumber gulp-uglify # Babel 6からpresetを指定しないといけなくなったので必要なプリセットも入れておきます。 $ npm install --save-dev babel-preset-react babel-preset-es2015
次に実際にreactのテストをするディレクトリを作成します。
$ mkdir react-test $ cd react-test
gulpfile.jsを作成し、以下のように記述します。
var gulp = require('gulp'), plumber = require('gulp-plumber'), uglify = require("gulp-uglify"), browserify = require('browserify'), babelify = require('babelify'), source = require('vinyl-source-stream'); // トランスパイル gulp.task('browserify', function() { browserify('./common/js/jsx/app.jsx', { debug: true }) .transform(babelify, { presets: ['es2015', 'react'] }) .bundle() .on("error", function (err) { console.log("Error : " + err.message); }) .pipe(source('bundle.js')) .pipe(gulp.dest('./common/js/')) .on('end',function(){ gulp.src(["./common/js/bundle.js"]) .pipe(plumber()) .pipe(uglify({mangle: false})) .pipe(gulp.dest("./common/js/min")) }) }); // watch gulp.task('watch',function(){ gulp.watch('./common/js/jsx/*.jsx', ['browserify']); }); gulp.task("default",['watch']);
パスなどはお好きな環境に合わせてください。
今回は[common/js/jsx/*.js]をwatchし変更があれば[common/js/jsx/app.jsx]をトランスパイルし、[common/js/bundle.js]に書き出し、さらにコンパイルして[common/js/min/bundle.js]に書き出すという流れです。
app.jsxはそれぞれのコンポーネントをrequireする感じで使うと煩雑にならずいい感じだと思います。
とりあえず動かしてみる
ではcommon/js/jsx/app.jsxを作成し、コンポーネントを作成してみます。
#common/js/jsx/app.jsx // Reactをインポート import React from "react"; import ReactDOM from "react-dom"; // コンポーネント class Test extends React.Component { render(){ return ( <h1>React.jsのテスト</h1> ); } } // レンダリング ReactDOM.render( <Test />, document.getElementById('container') );
まず、ReactとReactDOMをimportします。
コンポネントの書き方はclass [コンポーネント名] extends React.Componentという感じです。
別ファイルに切り分ける場合はexport default class [コンポーネント名] extends React.Component として、
import [コンポーネント名] from “ファイル名”;と書きます。
最後にコンポーネントを#containerにレンダリングしています。
注意すべき点は、render()で返す要素はwrapしている必要があります。2つ以上の要素が入っているとトランスパイルエラーになります。
さらに、classはclassNameに置き換える必要があり、閉じタグや、<img />などの閉じタグがない要素やスラッシュが省略できる要素もスラッシュがないとエラーになってしまいます。
ではindex.htmlに実際に表示してみたいと思います。
<div id="container"></div> <script src="common/js/min/bundle.js"></script>
gulpを実行。
$ gulp
このファイルにアクセスするとReactが実際に動いているのがわかると思います。
Demo.01
PropsとState
先ほどのデモではただ、静的なものを表示したにすぎません。
ReactではApiなどからjsonで取得した値をコンポーネントに渡して表示したり、変更したりということが行えます。
では実際にデータを表示してみます。
Reactのデータの種類にはPropsとStateの2種類があります。
値 | 値を指定するタイミング | 値の変更 |
---|---|---|
props | コンポーネント作成時 | × |
state | コンポーネント作成後 | ◯ |
だそうです。
つまり、Propsは変更しない値、Stateは変更する値を入れるということですね。
まずはPropsを指定してみます。
app.jsx上部に以下のように書き、コンポーネントにdata={data}のようにアトリビュートとして値を渡します。
// app.jsx上部に以下を var propsData = { name : 'Mineo Okuda'}; ... // レンダリング ReactDOM.render( <Test data={propsData} />, document.getElementById('container') );
コンポーネントに渡した値はthis.props.[データ名]で取得できます。
class Test extends React.Component { render(){ return ( <div>こんにちは、{this.props.data.name}さん</div> ); } }
今度はStateを使ってボタンクリックで数値をカウントするロジックを書いてみます。
class Test extends React.Component { // コンストラクター constructor(props) { super(props); this.state = { count : 0 }; } // ボタンクリック時にcountに1を足す _onClick(){ var _count = this.state.count +1; this.setState({ count : _count}); } render(){ return ( <div> こんにちは、{this.props.data.name}さん <div> {this.state.count} <button onClick={this._onClick.bind(this)}>click</button> </div> </div> ); } }
まず、コンストラクターでおまじないのようなsuper(props);を呼びます。
ここでthis.stateに初期値を代入することでstateを指定できます。
もちろんPropsを入れることもできます。
Stateを変更する際にthis.state.count= _count;という記述方法は推奨されていません。
かならずsetState()を呼ぶようにしてください。
これでボタンをクリックするたびに数字がカウントされていくロジックがかけました。
Demo.03
最後に
「長ったらしいな・・・」と思った方がいると思います。
そのとおり、Reactは少しのことでロジックが長くなってしまいます。
ですが、イベントをどこに書いているのか、何をしているのかが明瞭に書けます。
jQueryなどでイベントをバインドする際、ロジックをどこにでも書けるので大規模になってきた場合に修正が大変困難です。(実際自分でもソースを追っかけないといけないことがあります。)
Reactは大規模になってもコンポーネントを量産していくだけなのでロジックが分散することはありません。
ルールをしっかり決める事で開発がとてもしやすくなると思います。
今回は本当に触り程度しかご説明していませんが、Reactはもっとさまざまなことができます。
是非これを機会に活用してみてはいかがでしょうか?