最近流行りの React で簡単な UI を作ってみます。 React は仮想 DOM を使っているのが特徴の View のためのライブラリで、 DOM に状態を持ちません。
状態は DOM とは別に管理され、状態が変化するたびに仮想 DOM を構築します。状態の管理が簡単になる一方でパフォーマンスに悪影響がある、と思わせて仮想 DOM 同士の差分を計算し、その差分だけ実際の DOM に反映させるため、むしろ動作は速いようです。
必要な知識
bower
コマンドの使い方
React のインストール
React は bower で簡単にインストールできます。
$ bower install react
メッセージを表示するだけのコンポーネントを作ってみる
初めは React を使って画面に Hello, World! と表示してみます。 React とそれを使ったプログラムを HTML から読み込みます。 #view
は React で作った要素が追加される場所です。
<!DOCTYPE html>
<meta charset="utf-8">
<div id="view"></div>
<script src="bower_components/react/react.js"></script>
<script src="test.js"></script>
var Message = React.createClass({
render: function() {
return React.createElement('div', {}, 'Hello, World!');
}
});
var view = document.querySelector('#view');
React.render(React.createElement(Message, {}), view);
これを保存して Web ブラウザで開くと Hello, World! と表示されるはずです。
React で定義できる要素はコンポーネントと呼ばれます。
React.createClass
はコンポーネントを作成する関数です。引数として渡した render
は仮想 DOM をレンダリングするメソッドです。
React.createElement
は要素名やタグに、後で説明する props
を与えて (上の例だと {}
) 仮想 DOM を作成します。
React.render
は実際の DOM (上の例だと #view
) に仮想 DOM をレンダリングする関数です。
次は Hello, World! 以外のメッセージに切り替えられるように機能を追加します。
コンポーネントに値を値を渡す
外部から値を渡すには React.createElement
の第2引数にオブジェクトを渡せば可能です。
さっきの JavaScript を少しだけ変えてみます。
var Message = React.createClass({
render: function() {
var name = this.props.name || 'World';
return React.createElement('div', {}, 'Hello, ' + name + '!');
}
});
var view = document.querySelector('#view');
React.render(React.createElement(Message, { name: '太郎' }), view);
これを実行すると Hello, 太郎!
よ表示されるはずです。
React.createElement
の第2引数に与えた値に render
の中で this.props
として触っています。
name
を変更すればいろんな人にあいさつできます。
もっと UI らしいものを作る
テキストを表示するだけだとアレなので、もっと実際のアプリに近いものを作ってみます。
var Component = React.createClass({
getInitialState: function() {
return {
text: '',
messages: []
};
},
onTextChanged: function() {
this.setState({
text: this.refs.text.getDOMNode().value,
messages: this.state.messages
});
},
onButtonClicked: function() {
this.setState({
text: '',
messages: this.state.messages.concat([this.state.text])
});
},
render: function() {
return React.createElement('div', {},
React.createElement('input', {
type: 'text',
ref: 'text',
value: this.state.text,
onChange: this.onTextChanged
}),
React.createElement('button', {
onClick: this.onButtonClicked
}, '送信'),
this.state.messages.map(function(m, i) {
return React.createElement('div', { key: i }, m)
})
);
}
});
var view = document.querySelector('#view');
var dom = React.createElement(Component, {});
React.render(dom, view);
実行すると入力欄とボタンが表示されるはずです。ボタンを押すとメッセージが下に増えていくチャットのなりそこないです。
まず新しいのは state
です。その名の通りコンポーネントの状態を保持しているプロパティで一番初めに getInitialState
が呼ばれてそれがセットされます。 setState
で状態は変更でき、状態が変わるたびに render
が呼ばれて画面が更新されます。
React.createElement
の第2引数 に ref
を指定すると this.refs
からその要素にアクセスできるようになります。
input
要素を使っていますが、ただ作るだけだと value
の更新ができず、 onChange
で変更したタイミングで setState
する必要があります。少し面倒に思えるかもしれませんが、値の変更が常に1方向になるので結果的には管理が簡単なります。
ここまでやってきて React.createElement
がかなりたくさん登場しました。次はこれを簡単に書ける方法を試して見ます。
JSX を試す
JSX で検索すると色々同じ名前のものが出てきて残念な感じですが、 Facebook の言う JSX は JavaScript の中に書くことができる XML のような記法のことです。
当然そのままだと構文エラーなので、 JSXTransformer.js
を読み込んだ上で script
要素の type
に text/jsx
を指定する必要があります。
<!DOCTYPE html>
<meta charset="utf-8">
<div id="view"></div>
<script src="bower_components/react/react.js"></script>
<script src="bower_components/react/JSXTransformer.js"></script>
<script type="text/jsx" src="test.js"></script>
これで JavaScript の中では React.createElement
を JSX を使って書くことができます。
var Component = React.createClass({
getInitialState: function() {
return {
text: '',
messages: []
};
},
onTextChanged: function(value) {
this.setState({
text: this.refs.text.getDOMNode().value,
messages: this.state.messages
});
},
onButtonClicked: function(text) {
this.setState({
text: '',
messages: this.state.messages.concat([this.state.text])
});
},
render: function() {
return (
<div>
<input type="text" ref="text"
value={this.state.text}
onChange={this.onTextChanged} />
<button onClick={this.onButtonClicked}>
送信
</button>
{ this.state.messages.map(function(m, i) {
return <div key={i}>{m}</div>
}) }
</div>
);
}
});
var view = document.querySelector('#view');
var dom = <Component />;
React.render(dom, view);
React.createElement
だったところに XML 風の記法で書き込めています。ただの糖衣構文なので必ず使う必要はありませんが、簡潔にかけるのは便利そうです。
まとめ
- React は仮想 DOM を使った View のためのライブラリ
React.createClass
React.createElement
React.render
getInitialState
setState
- JSX