railsでreact(react-rails)とreduxを動かす

  • 125
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

流行りのfluxフレームワークreduxとreact-railsを試してみる。
reduxのexamplesにある、counterをreact-railsを使って書いてみます。
https://github.com/rackt/redux/tree/master/examples/counter

※以下のバージョンで書いてます。

  • rails 4.2.3
  • redux 3.0.4
  • react-rails 1.4.2
  • react 0.14.2

ソースは以下におきました。
ソースは@odk211さんからPR頂いてbabel6を使ったものになってます。
https://github.com/suzan2go/react-rails-redux-sample

事前準備

browserify-railsのインストール

Gemfileに以下を追加してbundle installしましょう。

gem 'browserify-rails'

reduxのサンプルはES6の書き方を沢山使ってますので、そのまま使うにはトランスパイラが必要になります。config/application.rbに以下を追加しましょう

config.browserify_rails.commandline_options = '-t babelify'

browserifybabelify、そしてbrowserify-railsに必要なbrowserify-incrementalをnpmで入れます。

npm install --save-dev browserify
npm install --save-dev browserify-incremental
npm install --save-dev babelify

babel6で動かす場合

babelify 7.0 以降を入れる場合など、babel6で動かす場合は以下も必要になるようです

npm install --save-dev babel-preset-es2015
npm install --save-dev babel-preset-react
npm install --save-dev babel-preset-stage-2

babel-preset-stage-2自体はなくても動かせるのですが、今回扱うサンプルの.babelrcstage-2の記述があったので、一応追加しています。

railsのアプリケーションrootに、.babelrcを追加します。

{
  "presets": ["es2015", "stage-2", "react"]
}

reduxのインストール

今回のexampleでは以下が必要になるのでnpm installします。1.0.0-rcよりreduxの中でもreactに特化した部分がreact-reduxに切りだされています。reactを使う場合はこちらも必要です。
https://github.com/rackt/redux/releases/tag/v1.0.0-rc

npm install --save react
npm install --save redux
npm install --save react-redux
npm install --save redux-thunk

react-railsでもreactが入りますが、今回はnpmで入れたreactを使うことにします。

react-railsのインストール

なにはともあれ、react-railsをインストールします。Gemfileに以下を追加してbundle installしましょう。

gem 'react-rails'

インストールが完了したら以下のコマンドを実行します。

rails g react:install

このコマンドを実行すると以下のファイル、ディレクトリが追加され、application.jsに記述が追加されます。

app/assets/javascripts/components.js
app/assets/javascripts/components/

application.jsは多分こんな感じになってるはず。

# application.js
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require react
//= require react_ujs
//= require components
//= require_tree .

npmでいれたreactを使うので、//=require reactは消しても大丈夫です。//= require_tree .は不要なので消しておきましょう。

Reduxのexamplesにあるcounterをreact-railsで動かす

前置きが長くなりましたが、いよいよreact-railsでreduxを動かしてみます。

reduxのexamplesを持ってくる

reduxのレポジトリに入っているexaplesから以下のフォルダをapp/assets/javascripts/components/配下に格納します。ファイルは他にもありますが、とりあえずこれだけあれば動かせます。

  • actions
  • components
  • containers
  • reducers
  • store

https://github.com/rackt/redux/tree/master/examples/counter

babel6で動かす場合

公式のcounterのサンプルと同じディレクトリにある.babelrcがあると、babel6では動きません。サンプルの.babelrcは削除して、前述の通りrailsのアプリケーションrootに.babelrcを作成してください。(この.babelrcを同じように書き換えても動きます。)

{
  "presets": ["es2015", "stage-2", "react"]
}

components.jsを書き換える

react-railsをインストールしたときに作成したcomponents.jsを書き換えます。
Root.jsに定義されているRootがカウンターアプリのコンポーネントなので、これをreact-railsreact_componentヘルパから呼べるようにします。


window.React = require('react');
window.React = require('react-dom');
window.Root  = require('./components/containers/Root.js');
// babel6の場合
// window.Root  = require('./components/containers/Root.js').default;

Viewファイルから呼び出す

Viewファイルにreact_componentヘルパーを記述してブラウザからアクセスしてみると。

<%= react_component('Root') %>

こんな感じで表示されるようになるはず!

Kobito.vSZjlv.png

react_componentヘルパーに渡したパラメータで初期値をセットできるようにする

react_componentヘルパーに初期値を渡して、サーバサイドレンダリングできるようにしてみます。

Viewファイルを書き換える

まず先ほど記述したViewファイルを以下の様に書き換えます。素のReactコンポーネントの場合はこれで値を渡すことがますが、今回はreduxを通しているのでこれだけでは値はセットされません。

<%= react_component('Root', {counter: 10}) %>

カウンター値をセットするactionを定義する

actions/counter.jsに以下を追記します。

export const SET_COUNTER = 'SET_COUNTER';

export function setCounter(counter) {
  return {
    type: SET_COUNTER,
    counter: counter
  };
}

カウンター値をセットするstoreを定義する

reducers/counter.jsに以下を追記します。(reduxでは他のフレームワークでstoreとなっているものをreducerと呼ぶようです。)

// SET_COUNTERを追記
import { INCREMENT_COUNTER, DECREMENT_COUNTER, SET_COUNTER } from '../actions/counter';

export default function counter(state = 0, action) {
  switch (action.type) {
  case INCREMENT_COUNTER:
    return state + 1;
  case DECREMENT_COUNTER:
    return state - 1;
  // SET_COUNTERに対応する処理を追加します。
  case SET_COUNTER:
    return action.counter;
  default:
    return state;
  }
}

componentWillMountからsetCountを呼ぶ

containers/Root.jsに以下を追記します。サーバサイドレンダリングを行う場合、サーバ側で行う処理はReactコンポーネントのライフサイクルの中でもcomponentWillMountに記述する必要があります。
https://facebook.github.io/react/docs/component-specs.html#mounting-componentwillmount

import {setCounter} from '../actions/counter'

export default class Root extends Component {
  componentWillMount() {
    store.dispatch(setCounter(this.props.counter));
  }
 // 以下省略

これで準備は完了です!もう一度アクセスするとこんなかんじになるはず。
Kobito.n23TSI.png

サーバサイドレンダリング

react-railsを使う大きなメリットですね。ヘルパーに{prerender: true}とするだけでサーバサイドでのレンダリングが可能になります。試しにブラウザでjavascriptを無効にしても、最初に表示される画面は同じになるはずです。

<%= react_component('Root', {counter: 10}), {prerender: true} %>

感想・所感

react-railsとfluxについて書いてある情報が少なくて困った。react_component経由で値を渡すところとか結構手探りなので、flux的におかしいとかあればご指摘ください…
redux以外も結構そうみたいなんですが普通にES6、なんならES7の記法で当たり前のように書いてあるものが多くて、今のプロジェクトやサービスでは使わないにしてもES6読めるようにしとく必要があるなーと感じました。
reactもfluxについても今回はじめてちゃんと勉強したので、react、flux、ES6全部あんまり良くわかっていないところからのスタートはかなりきつかったです。