This article describes how to start React on Rails.
    
    
    
π» Instration Node with Mac Homebrew brew upgrade brew install node 
πΌ Creating React Sample App npm install -g create-react-app create-react-app hello-world cd  hello-worldnpm start 
π Using React on Rails In this section, we are using RubyGem react_on_rails 
At first, add the following to your Gemfile and bundle install:
Commit this to git and please run following commands:
rails g react_on_rails:install bundle && npm install foreman start -f Procfile.dev 
Please see http://localhost:3000/hello_world .
All JavaScript in React On Rails is loaded from npm: react-on-rails.
cd  client && npm i --saveDev react react-on-rails react-helmet nprogress
π‘ Controller Supporting following flow:
Return HTML in first request 
In page transition, return JSON 
Do not show JSON when returning with browser back 
 
class  ApplicationController  < ActionController::Base  protect_from_forgery with:  :exception    private   def  _action_path      "#{controller_path} ##{action_name} "    end    def  _common_props      { actionPath:  _action_path }   end    def  _render_for_react (props:  {}, status:  200 )      if  request.format.json?       response.headers['Cache-Control' ] = 'no-cache, no-store'        response.headers['Expires' ] = 'Fri, 01 Jan 1990 00:00:00 GMT'        response.headers['Pragma' ] = 'no-cache'        render(         json:  {           rootProps:  _common_props.merge(props)         },         status:  status       )     else        render(         html:  view_context.react_component(           'Router' ,           props:  {             rootProps:  _common_props.merge(props)           }.as_json         ),         layout:  true ,         status:  status       )     end    end  end 
Usage example is as follows:
class  ArticlesController  < ApplicationController     def  index      _render_for_react(       props:  {         articles:  Article.limit(20 )       }     )   end  end 
 πΈ JavaScript Entry Point Entry point of shared JavaScript code is like this:
import  ReactOnRails from  "react-on-rails" ;import  Router from  "../components/Router" ;ReactOnRails.register({ Router }); 
Router 
Router selects Component by actionPath 
Display progress bar during page transition 
Scroll to a top of a page after page transition 
Adjust browser history using pushState / popState 
 
import  React from  "react" ;import  NProgress from  "nprogress" ;import  Articles from  "../components/Articles" export  default  class  Router  extends  React .Component    static  propTypes = {     rootProps:  React.PropTypes.object,   };   static  childContextTypes = {     onLinkClick: React.PropTypes.func,   };   componentDidMount() {     window .addEventListener("popstate" , () => {       this .transitTo(document .location.href, { pushState : false  });     });   }   constructor (...args) {     super (...args);     this .state = {       rootProps:    this .props.rootProps,     };   };   getComponent() {     switch  (this .state.rootProps.actionPath) {       case  "articles#index" :         return  Articles;            }   };   getChildContext() {     return  {       onLinkClick: this .onLinkClick.bind(this ),     };   };   onLinkClick(event) {     if  (!event.metaKey) {       event.preventDefault();       const  anchorElement = event.currentTarget.pathname ? event.currentTarget : event.currentTarget.querySelector("a" );       this .transitTo(anchorElement.href, { pushState : true  });     }   };   transitTo(url, { pushState }) {     NProgress.start();     $.ajax({       url: url,       dataType: 'json' ,       cache: false ,       success: function (props )          if  (pushState) {           history.pushState({}, "" , url);         }         this .setState({rootProps : props.rootProps});         NProgress.done();         if (typeof  window  !== 'undefined' ) {           window .scrollTo(0 , 0 );         }       }.bind(this ),       error: function (xhr, status, err )          NProgress.done();         console .error(url, status, err.toString());       }.bind(this )     });   };   render() {     const  Component = this .getComponent();     return  <Component  {...this.state.rootProps } key ={this.state.requestId}  /> ;   }; } 
Link When a user clicks a link, a client communicates with the server with XHR and post a state to Router. 
So I use the original Link tag instead of a tag.
import  React from  "react" ;export  default  class  Link  extends  React .Component    static  contextTypes = {     onLinkClick: React.PropTypes.func,   };   onClick(event) {     this .context.onLinkClick(event);   }   render() {     return (       this  .onClick.bind(this )} {...this.props}>        {this .props.children}       </a>      );   } }; 
Link example is as follows:
π£ Title/Meta Tags import  React from  "react" ;import  Helmet from  "react-helmet" ;import  {siteName, siteBaseUrl} from  "../constants/service" ;export  default  class  Articles  extends  React .Component    pageUrl() {     return  siteBaseUrl + "/articles" ;   }   pageTitle() {     return  "huga" ;   }   pageDescription() {     return  "hoge" ;   }   render() {     return (       
                   title={this .pageTitle()}           link={[             {rel : "canonical" , href : this .pageUrl()},             {rel : 'alternate' , href : this .pageUrl()},           ]}           meta={[             {property : "og:url" ,          content : this .pageUrl()},             {property : "og:title" ,        content : this .pageTitle()},             {property : "og:description" ,  content : this .pageDescription()},             {name : "description" ,         content : this .pageDescription()},           ]}         />            </div>    );   } }  
 π Run npm install in ElasticBeansTalk This is a script to use webpack in deploy process of ElasticBeansTalk.npm install beforerake assets: precompile.10 is depend on each environment, so please fix it.)
files:   "/opt/elasticbeanstalk/hooks/appdeploy/pre/10_install_node_modules.sh"  :      mode:  "000744"     owner:  root     group:  root     content:  |       #!/usr/bin/env bash       set -xe       EB_APP_STAGING_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k app_staging_dir)       cd $EB_APP_STAGING_DIR/client       npm install     encoding:  plain 
π Special Thanks This article has created by the following Japanese articles. Thank you very much, @r7kamura !
 π Sample App 
    
    
    
    
    
    π₯ Recommended VPS Service 
    
    VULTR Check Benchmark Results