Rails 5.1でreact環境を作ってみた


[Rails 5.1.0.beta1 試してみた - Qiita](http://qiita.com/kikunantoka/items/ab9d612abc213c734183)

こちらの続き

js周りは、

- yarnを使用
- webpackを使用
	- [rails/webpacker: Use Webpack to manage app-like JavaScript modules in Rails](https://github.com/rails/webpacker)

このあたりが変更点となり、モダンフロントを取り入れる形となっている
（cf. [Rails 5.1の変更点まとめ - Qiita](http://qiita.com/jnchito/items/b0b47ecfc33de4f9b72f)）

## 所感
今までwebpack.config書いて、頑張ってRailsに統合していたモダンフロントがよしなに構築されている


## 実行環境
- Rails 5.1.0.beta1
- Ruby 2.4.0
- node 6.10.0

## 作業履歴
[Commits · kikunantoka/rails5-1-0-beta1](https://github.com/kikunantoka/rails5-1-0-beta1/commits/master)

## hello world from webpacker

rails new --webpackすると

```js:app/javascript/packs/application.js
// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.
//
// To reference this file, add <%= javascript_pack_tag 'application' %> to the appropriate
// layout file, like app/views/layouts/application.html.erb

console.log('Hello World from Webpacker')
```

このファイルが生成されるが、この状態でrails sしてもconsole logにhello world from webpackerは表示されない

```ruby:app/view/layouts/application.html.erb
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
```

webpack helperのjavascript_pack_tagを使う
（cf. [Rails & Webpackerでフロントエンド開発環境を整える - Qiita](http://qiita.com/hiyamamoto/items/e0a30b4799314174b80f)）

```ruby:app/view/layouts/application.html.erb
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
```

![01-console.png](https://qiita-image-store.s3.amazonaws.com/0/30233/f6d84a1a-fa73-0b86-d70b-b054055071b3.png "01-console.png")

## Hot Reload してみる

下記コメントアウトをコメントインする

```ruby:app/config/environments/development.rb
Rails.application.configure do
  # Make javascript_pack_tag load assets from webpack-dev-server.
  config.x.webpacker[:dev_server_host] = "http://localhost:8080"
```

bin/配下を見ると分かるが、webpackをラップしたwebpacker用のコマンドが用意されている

- bin/webpack
- bin/webpack-dev-server
- bin/webpack-watcher

`bin/webpack-dev-server` を使うと `http://localhost:8080` でコンパイルされたjsファイルがサーブされる

```console:console
$ rails s

--- another tab

$ bin/webpack-dev-server
```
![02-hot-reload.gif](https://qiita-image-store.s3.amazonaws.com/0/30233/bb6eb71d-8366-1aec-fedc-2f4bd2d1f933.gif "02-hot-reload.gif")

## Foreman を入れる

コマンドを２つ叩くのが面倒なので、

```ruby:Gemfile
group :development do
  gem 'foreman'
end
```

```console:Procfile
rails: PORT=3000 rails s
webpack: bin/webpack-dev-server
```

上記を追加することで

```console:console
$ foreman start
```

でrailsサーバとnodeサーバが立ち上がる

## Reactを入れる
yarn addしようとしていたら、コマンドがあった

```console:console
$ rails webpacker:install:react
```

yarn addやreactを使うためのwebpackの設定などを自動で書き加えてくれて、下記のファイルを生成してくれる

```js:app/javascript/packs/hello_react.js
// Run this example by adding <%= javascript_pack_tag 'hello_react' %> to the head of your layout file,
// like app/views/layouts/application.html.erb. All it does is render <div>Hello React</div> at the bottom
// of the page.

import React from 'react'
import ReactDOM from 'react-dom'

class Hello extends React.Component {
  render() {
    return <div>Hello {this.props.name}!</div>
  }
}

document.addEventListener("DOMContentLoaded", e => {
  ReactDOM.render(<Hello name="React" />, document.body.appendChild(document.createElement('div')))
})
```

コメントにあるように、このファイルをlayoutファイルで読み込む

```ruby:app/views/layouts/application.html.erb
<%= javascript_pack_tag 'hello_react', 'data-turbolinks-track': 'reload' %>
```

DOMの一番下に

Hello React!

が追加される🎉

## せっかくなので、stateを変更できるようにする
```js:app/javascript/packs/hello_react.js
import React from 'react'
import ReactDOM from 'react-dom'

class Hello extends React.Component {
  constructor(props) {
    super(props)
    this.state = { name: this.props.name }
  }

  updateName(name) {
    this.setState({ name });
  }

  render() {
    return (
      <div>
        <h3>
          Hello, {this.state.name}!
        </h3>
        <hr />
        <form >
          <label htmlFor="name">
            Say hello to:
          </label>
          <input
            id="name"
            type="text"
            value={this.state.name}
            onChange={(e) => this.updateName(e.target.value)}
          />
        </form>
      </div>
    )
  }
}

document.addEventListener("DOMContentLoaded", e => {
  ReactDOM.render(<Hello name="kikunantoka" />, document.body.appendChild(document.createElement('div')))
})
```
![04-hello-kikunantoka.gif](https://qiita-image-store.s3.amazonaws.com/0/30233/56ee911f-fc6a-2231-e4f2-cdbb34a7c404.gif "04-hello-kikunantoka.gif")

## SSRとか
今のところ、react_on_rails使うことになりそう

## 終わりに
以上、rails5.1にreactを入れるまででした
フロントの環境を簡単に整えられて良さそうですね！