This is ...
はじめての React.js
Virtual DOM と JSX
- ReactはjQueryのようにHTMLからDOMを組み立てません。
- 最初からJavaScriptのオブジェクトでDOMの構造を組み立て管理しています。
- JavaScriptで組み立てられた DOM(Virtual DOM)だと人間が読むのにツライので、JSXというHTMLをJavaScriptオブジェクトにコンパイルする仕組みが用意されています。
jQuery
$('#id').append('<div>Seconds Elapsed' + this.state.secondsElapsed + '</div>');
JSで書いたReact
// Objectで仮想DOMを作る。
return React.createElement(
"div", null, "Seconds Elapsed: ", this.state.secondsElapsed
);
JSXで書いたReact
// JSX
return (
<div>Seconds Elapsed: {this.state.secondsElapsed}</div>
);
- JSXの中に { } でHTMLの中に動的なデータやJavacriptを挿入することができます。(ERBの<% %>、PHPのとだいたい同じです。JavaScriptでERB書いてる感じです)
コンポーネント
- 幾つかの HTML で組み立てられた作られたパーツです。
- Bootstrap の Compornents のようなものです。
実例
- コンポーネントは入れ子にできます。コンポーネントを上手に分けることができればとてもすっきりして見やすい。
- 同じ階層のコンポーネント間でデータをやり取りするときは親コンポーネントを作って中継します。
コンポーネントの要素
- React のコンポーネントの要素について軽く触れます。
render()
- コンポーネントに必ず定義しないといけない関数。
- 仮想DOMをreturnします。
props
- コンポーネントに外部から与えられたデータ
- コンポーネントの中で変更してはいけない
{/* HogeComponent 内で `this.props.foo` => "bar" という感じに取り出せる */}
<div>
<HogeComponent foo="bar" />
</div>
state
- コンポーネント内部で管理するデータ
- コンポーネントの外から変更してはいけない
- 変更するときは
setState()
メソッドを使う。-
setState()
で state を変更すると、変更の差分が再描画される。
-
key
- 同じコンポーネントをリストで繰り返し配置する場合、Reactが要素の追加・削除・移動などを検出するために、ユニークになるデータを与えてあげる必要があります。
- key は設定しなくても動作はしますが、key を設定してあげることでReactがDOMの再描画を効率良く行ってくれるようになるのでパフォーマンスが上がります。
RailsでReactするための設定
- react-rails というGemを使います。
Gemfile
gem 'react-rails'
- generator を使うといい感じに環境ができる。
sh
rails g react:install
- コンポーネントも generator で作れる。
sh
rails g react:component [コンポーネント]
# => app/assets/javascripts/components/[コンポーネント].js.jsx ができあがる
- ヘルパーでコンポーネントをビューに設置する
erb
<%= react_component('[コンポーネント]') %>
- JSXはES6シンタックスが使えます。アロー関数
() => {}
が便利です。 - 拡張子を
.js.jsx.coffee
にすると CoffeeScript でJSXを書くこともできます。
JSX の注意点
- JavaScriptの予約語とかぶってるアトリビュートがリネームされている
- class => className
- for => htmlFor
- 閉じタグがない場合は
/>
でタグを閉じる。XHTMLっぽい。<br />
- jQueryなどで外部からReactでレンダリングしたDOMをいじるとうまく動かない時があります。
- 使う箇所の住み分けができていれば jQuery と一緒に使っても大丈夫。Bootstrapも使えます。
- エラーログが丁寧で解りやすいので、デベロッパーツールのコンソールみましょう。
React.js ハンズオン
環境
- rails: 4.2.4
- react-rails: 1.5.0
- github: startup-technology/hajimete-no-react
準備
$ git clone git@github.com:startup-technology/hajimete-no-react.git
$ cd hajimete-no-react
$ bundle install
- react-rails を追加
Gemfile
gem 'react-rails', '~> 1.5.0'
$ bundle install
- react の環境設定
$ rails g react:install
create app/assets/javascripts/components
create app/assets/javascripts/components/.gitkeep
insert app/assets/javascripts/application.js
insert app/assets/javascripts/application.js
insert app/assets/javascripts/application.js
create app/assets/javascripts/components.js
コンポーネントを作る
$ rails g react:component Hello
create app/assets/javascripts/components/hello.js.jsx
- このようなファイルができている
app/assets/javascripts/components/hello.js.jsx
var Hello = React.createClass({
render: function() {
return <div />;
}
});
コントローラーとビューを作成
$ rails g controller hello
- HelloController に index アクションを追加
app/controllers/hello_controller.rb
class HelloController < ApplicationController
def index
end
end
- routes を設定
config/routes.rb
root 'hello#index'
- ビューにReactコンポーネントを追加します
app/views/hello/index.html.erb
<%= react_component 'Hello' %>
確認してみる
- コンポーネントを修正します
app/assets/javascripts/components/hello.js.jsx
var Hello = React.createClass({
render: function() {
return (
<div>
<h1>Hello React!</h1>
</div>
);
}
});
- railsを起動して確認してみましょう
$ rails s
リストを作ってみる
- HelloList というコンポーネントを作って並べてみます。
$ rails g react:component HelloList
- HelloList は、親コンポーネントから
hello
というprops
を
app/assets/javascripts/components/hello_list.js.jsx
var HelloList = React.createClass({
render: function() {
return (
<li>Hello {this.props.hello}</li>
);
}
});
- Hello コンポーネントも少し直します。
- Hello コンポーネントの中に HelloList コンポーネントを設置してみます。
app/assets/javascripts/components/hello.js.jsx
var Hello = React.createClass({
render: function() {
return (
<div>
<h1>Hello React!</h1>
<ul>
<HelloList hello="hoge" />
<HelloList hello="fuga" />
</ul>
</div>
);
}
});
- 確認してみましょう
リストを動的に作ってみる
- Hello コンポーネントをさらに直します
-
getInitialState
で、state
の初期値を設定します。 -
map
を使い、配列でエレメントを作成しています。 - エレメントを一旦変数に格納してから埋め込むことができます。
app/assets/javascripts/components/hello.js.jsx
var Hello = React.createClass({
getInitialState: function() {
return {
hello: ['hoge', 'fuga']
}
},
render: function() {
var helloList = this.state.hello.map(hello => {
return <HelloList hello={hello} />;
});
return (
<div>
<h1>Hello React!</h1>
<ul>
{helloList}
</ul>
</div>
);
}
});
- 先ほどと同じ内容が表示されていると思います。
- この時、コンソールを見ると Warning が発生しています。
- Reactに配列で要素を設置する場合はユニークな
key
を設定してあげる必要があります。 - HelloListにユニークな
key
を渡すように修正してみましょう。
app/assets/javascripts/components/hello.js.jsx
var Hello = React.createClass({
getInitialState: function() {
return {
hello: [
{id: 1, text: 'hoge'},
{id: 2, text: 'fuga'}
]
}
},
render: function() {
var helloList = this.state.hello.map(hello => {
return <HelloList key={hello.id} hello={hello.text} />;
});
return (
<div>
<h1>Hello React!</h1>
<ul>
{helloList}
</ul>
</div>
);
}
});
- これでワーニングが消えたはずです。
フォームを作ってみる
- HelloForm コンポーネントを作ります。
$ rails g react:component HelloForm
- JSXでもHTMLと同様に
onChange
などのイベントハンドラを設定することができます。- イベントハンドラの設定は
onChange={this.foge}
のように関数自体を渡していることに注意してください。 - HTML と同じ感覚で
onChange={this.foge()}
のように書いてしまうと、render の時に関数が実行されてしまいます。(ハンドラの中でsetState
していると無限ループになります)
- イベントハンドラの設定は
app/assets/javascripts/components/hello_form.js.jsx
var HelloForm = React.createClass({
getInitialState: function() {
return {
value: ''
}
},
handleChange: function(e) {
this.props.onChangeForm(e.target.value);
},
render: function() {
return (
<input type="text" onChange={this.handleChange} />
);
}
});
- props に関数を渡すと、子コンポーネントから親コンポーネントに引数でデータを渡すことができるようになります。
app/assets/javascripts/components/hello.js.jsx
var Hello = React.createClass({
getInitialState: function() {
return {
hello: [
{id: 1, text: 'hoge'},
{id: 2, text: 'fuga'}
],
value: 'React!'
}
},
handleChangeForm: function(value) {
this.setState({ value: value });
},
render: function() {
var helloList = this.state.hello.map(hello => {
return <HelloList key={hello.id} hello={hello.text} />;
});
return (
<div>
<h1>Hello {this.state.value}!</h1>
<HelloForm onChangeForm={this.handleChangeForm} />
<ul>
{helloList}
</ul>
</div>
);
}
});
- このようになります。
まとめ
- オライリーから本が出ています。入門 React
- Qiitaの記事だと 一人React.js Advent Calendar 2014 、react-railsを使ってReactのTutorialをやってみる などが分かりやすいと思います。