React-Router(react-router-dom)とReduxとRailsを組み合わせる

React-Router(react-router-dom)とReduxとRailsを組み合わせる

React-Router(react-router-dom)とReduxとRailsを組み合わせる

React-Router(react-router-dom)とReduxとRailsを組み合わせる へのコメントはまだありません

はじめに

React+Redux+RailsでSPAアプリを作ることになったので、あれこれ調べたのでメモです。
SPAというと、当然ですが、1つのページであれこれできちゃうものを作らなきゃいけないわけで・・・
そうなるとコンテンツ制御の仕組みが必要です。そこで登場するのがReact-Router-Dom。
で、これ単体では使い方簡単なんですが、RailsとReduxを絡めて動作させる方法が分からなかったので
あれこれ調べて、なんとか動くところまでたどり着いたので、メモを公開します。
React-Routerは古いようで、React-Router-Domにしてみました。。
ドキュメントが超少なくてまいりました。

完成図はこんな感じ。
青いところがメニューで、クリックすると、下のコンテンツがReact-Routerで入れ替わります。

rr-2

ソースコードはGitHubで公開しています。利用方法は、記事の末尾を参照ください。

Railsプロジェクト作成

[bash]
$ rails new react_router_with_redux

$ cd react_router_with_redux/
[/bash]

Gemを調整して、bundle install

[bash]
$ nano Gemfile
[/bash]

[bash]
gem ‘therubyracer’, platforms: :ruby
gem ‘react-rails’
gem ‘browserify-rails’
[/bash]

[bash]
$ bundle install
[/bash]

application.rbを編集

作った ES6(JavaScriptのバージョン)のソースをES5に自動変換するための設定を追記
config.browserify_rails の行を追加

config/application.rb

[bash]
require_relative ‘boot’

require ‘rails/all’

# Require the gems listed in Gemfile, including any gems
# you’ve limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module RailsRedux
class Application < Rails::Application # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers # -- all .rb files in that directory are automatically loaded. + config.browserify_rails.commandline_options = '-t babelify' end end [/bash]

Rails に Reactインストール

[bash]
$ rails g react:install
[/bash]

application.jsの編集

app/assets/javascripts/application.js

・Reactは npmでインストールしたものを使うのでカット。
・require_tree . もカット

変更前

[bash]
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require react
//= require react_ujs
//= require components
//= require_tree .
[/bash]

変更後

[bash]
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require react_ujs
//= require components
[/bash]

React、Redux、etc…の準備(node_modules)

React、Redux、React-Routerその他諸々を npm を使ってインストールします。

[bash]
$ npm init -y
$ npm install –save-dev browserify browserify-incremental babelify babel-preset-es2015 babel-preset-react

$ npm install –save react react-dom react-redux redux redux-thunk react-router-dom

[/bash]

.babelrc ファイルをRailsのルートフォルダに作成

[bash]
{
“presets”: [“es2015”, “react”]
}
[/bash]

Reduxの標準的なフォルダを作成

[bash]
$ cd app/assets/javascripts/
$ mkdir actions containers reducers
[/bash]

components.js編集

app/assets/javascripts/components.js

アプリ名は 「MyApp」とします。

myapp.jsはアプリのエントリーポイントとなるJSファイルです。ここに定義したクラス名(const宣言)を
windowの下にセット(変数として公開)してやる。

変更前

[bash]
//= require_tree ./components
[/bash]

変更後

[bash]
window.React = require(‘react’);
window.ReactDOM = require(‘react-dom’);
window.MyApp = require(‘./myapp.js’);

[/bash]

Reduxでカウンターアプリ、+静的ページをひたすら作る

ここ以降、しばらくは、Reduxでカウンターのインクリメント、デクリメントできるアプリを作ります。
加えて、静的ページもいくつか作ります。
何も考えずにソースをコピーしていってやってください・・・

app/assets/javascripts/actions/index.js
[bash]
export const counter_increment = () => {
return {
type: “INCREMENT”
}
}

export const counter_decrement = () => {
return {
type: “DECREMENT”
}
}

[/bash]

app/assets/javascripts/components/About.js
[bash]
import React from “react”

const About = () => {
return (

This is About

)
}

export default About

[/bash]

app/assets/javascripts/components/Contact.js
[bash]
import React from “react”

const Contact = () => {
return (

This is Contact Page

)
}

export default Contact

[/bash]

app/assets/javascripts/components/Counter.js
[bash]
import React from “react”

const Counter = ({counter, onIncrement, onDecrement}) => {

return (


Counter = {counter}

)
}

export default Counter

[/bash]

app/assets/javascripts/components/Top.js
[bash]
import React from “react”

const Top = () => {
return (

This is Top Page

)
}

export default Top

[/bash]

ここ withRouter という react-router-dom のクラスを使ってます。

app/assets/javascripts/containers/CCounter.js
[bash]
import {connect} from “react-redux”
import { withRouter } from ‘react-router-dom’
import {counter_increment, counter_decrement} from “../actions/index”
import Counter from “../components/Counter”

const mapStateToProps = (state) => {
return {
counter: state.counter
}
}

const mapDispatchToProps = (dispatch) => {
return {
onIncrement: () => {
dispatch(counter_increment())
},
onDecrement: () => {
dispatch(counter_decrement())
}
}
}

const CCounter = withRouter(connect(mapStateToProps, mapDispatchToProps)(Counter))

export default CCounter

[/bash]

app/assets/javascripts/reducers/counter.js
[bash]
const counter = (state = 0, action) => {
switch (action.type) {
case “INCREMENT”:
return state + 1
case “DECREMENT”:
return state – 1
default:
return state
}
}

export default counter

[/bash]

app/assets/javascripts/reducers/root.js
[bash]
import {combineReducers} from “redux”
import counter from “./counter”

const rootReducer = combineReducers({
counter: counter
})

export default rootReducer

[/bash]

ここまでで、とりあえず、カウンターアプリと、静的ページは出来上がり。
これ以降、アプリのエントリーポイント、React-Router周りに必要な処理を記載します。

アプリのエントリーポイント

app/assets/javascripts/myapp.js
[bash]
import React from “react”
import {createStore} from “redux”
import rootReducer from “./reducers/root”
import Root from “./components/Root”

class MyApp extends React.Component{
render(){
let store = createStore(rootReducer)

return (

)
}
}

export default MyApp

[/bash]

アプリケーションRoot

app/assets/javascripts/components/Root.js
[bash]
import React from “react”
import {Provider} from “react-redux”
import { BrowserRouter as Router, Route} from “react-router-dom”
import App from “./App”
import Top from “./Top”
import About from “./About”
import Contact from “./Contact”
import CCounter from “../containers/CCounter”

const Root = ({store}) => {

return (






}/>



)
}

export default Root

[/bash]

アプリケーションのトップページ

app/assets/javascripts/components/App.js
[bash]
import React from “react”
import {NavLink} from “react-router-dom”

class App extends React.Component {

render(){
return (

This is React Redux ReactRouter App

  • Top
  • Counter
  • About
  • Contact

{this.props.children}

)
}
}

export default App

[/bash]

Rails でコントローラーとビューを作成

[bash]
$ rails g controller myapp index

[/bash]

ビューを調整

ビューを調整して、SPAアプリのコンポーネントを出力します。

app/views/myapp/index.html.erb
[bash]
<%= react_component("MyApp") %>
[/bash]

ルーティングの調整

React-Routerで ページ移動するたびに myapp/xxxx へ移動しますが、
このパスを myapp#index に割り当ててやる。

config/routes.rb
[bash]
Rails.application.routes.draw do
get ‘myapp/index’
get ‘myapp/*path’, to: ‘myapp#index’

# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end

[/bash]

デザイン調整

app/assets/stylesheets/myapp.scss
[bash]
// Place all the styles related to the first controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

div.app{
ul.menus{
margin: 0;
padding: 0;

li{
float: left;
list-style: none;
width: 100px;
background-color: #346299;
padding: 15px;
padding-top: 20px;
border-right: 1px solid #cccccc;

a {
color: #ffffff;
}

a.active{
color: #efe250;
}
}
}

div.clear{
clear: both;
}

[/bash]

動作確認

[bash]
$ rails s
[/bash]

http://localhost:3000/myapp/index

以下のようなページが表示されれば、成功。
カウンターのページで、ボタンをクリックすると、カウンターが増減していたら、
Redux+React-Routerの組み合わせがうまく機能しているということになります。

rr-1

rr-2

rr-3

rr-4

プログラムからページ(Route)を切り替える

ボタンのクリックアクションなどでページを切り替えたい場合があると思います。
正式な方法かわかりませんが、以下の方法で出来ました。
Counterページから、Contactページに移動したらOKです。

プロパティに historyというのが存在するみたいで、それを利用します。
app/assets/javascripts/components/Counter.js
[bash]
import React from “react”

const Counter = ({counter, onIncrement, onDecrement, history}) => {

return (


Counter = {counter}

)
}

export default Counter

[/bash]

ボタンクリック
rr-10

Contactページヘ移動
rr-11

GitHubソースの利用方法

このソースはGitHubで公開していますので、ご自由に利用ください。

インストール手順

[bash]
$ git clone https://github.com/h-mito/react_router_with_redux
$ cd react_router_with_redux
$ bundle install
$ npm install
[/bash]

動作確認

[bash]
$ rails s
[/bash]

ブラウザーで以下のURLへアクセス
http://localhost:3000/myapp/index

以上

About the author:

Related Posts

Leave a comment

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)

Back to Top