React_on_rails v9 makes passing props from server side a breeze, therefore making server side rendering so simple when
prerender
is set to true. But the challange one faces is when trying to implements React Router v4.
The isssue with react router is inability to pass props from server side
I believe the documentation on upgrading from v7 to v9 will clear this issue -https://github.com/shakacode/react_on_rails/issues/809#issuecomment-334344969. But while I am waiting on that, I think we can still do something to profer solution to the routing issue.
Below are some steps to reproduce:
app/javascript/bundles/RailsNg/components/ServerHome.jsx
import React from 'react';
import ReactDOMServer from 'react-dom/server'
import { StaticRouter } from 'react-router';
import routes from './routes/routes';
const RailsNgOne = (props, railsContext) => {
const { location } = railsContext;
const context = {};
return (
<StaticRouter
location={location}
context={context}
>
{routes}
</StaticRouter>
);
};
global.React = React
global.ReactDOMServer = ReactDOMServer
export default RailsNgOne
app/javascript/bundles/RailsNg/components/ClientHome.jsx
import React from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import routes from './routes/routes';
export default (props, railsContext) => {
return (
<Router>
{routes}
</Router>
);
};
app/javascript/bundles/RailsNg/components/routes/routes.jsx
import React from 'react';
import { Route, Switch } from 'react-router';
import RailsNg from '../RailsNg';
export default (
<Switch>
<Route exact path="/" component={RailsNg} />
</Switch>
);
app/javascript/bundles/RailsNg/components/RailsNg.jsx
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Footer from './Footer'
import RailsNgHeader from './RailsNgHeader';
export default class RailsNg extends React.Component {
render(){
return(
<div className="landing-container">
<div className="landing-dashboard">
<RailsNgHeader logo={this.props.logo} />
<div className="dashboard-container">
<div className="dashboard-title">
<h2>Rails</h2><h1>NG</h1>
</div>
<div className="rails-logo">
<img src={this.props.railslogo} alt="railslogo" className="rails-logo" />
</div>
<div className="dashboard-text">
<p>An Acive Ruby on Rails Forum.</p>
<p>this Landing page is SSR</p>
</div>
<div className="dashboard-button-container">
<a href="#">
<div className="dashboard-button">
<p>GET STARTED</p>
</div>
</a>
</div>
</div>
</div>
<div className="dashboard-advert">
<image src={this.props.advert} alt="advert" className="dashboard-advert"/>
</div>
<Footer instagram={this.props.instagram} twitter=
{this.props.twitter} medium={this.props.medium} />
</div>
)
}
}
app/javascript/packs/rails-ng-bundles.js
import ReactOnRails from 'react-on-rails';
import RailsNgOne from '../bundles/RailsNg/components/ClientHome';
ReactOnRails.register({
RailsNgOne
})
app/javascript/packs/clientRegistration.js
import ReactOnRails from 'react-on-rails';
import RailsNgOne from '../bundles/RailsNg/components/ClientHome';
ReactOnRails.register({
RailsNgOne
})
app/views/rails_ng/index.html.erb
<%= react_component("RailsNgOne", props: @images, prerender: true, raise_on_prerender_error: true, trace: true) %>
app/views/layouts/rails_ng.html.erb
<!DOCTYPE html>
<html>
<head>
<title>RailsNg</title>
<%= csrf_meta_tags %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': true %>
<%= javascript_pack_tag 'rails-ng-bundle'%>
</head>
<body>
<div class="landing-Header">
<div class="header-button-container">
<div class="landing-button.login">
<%= link_to "Log Out", destroy_user_session_path, method: :delete %>
</div>
</div>
</div>
<%= yield %>
</body>
</html>
app/controllers/rails_ng_controller.rb
# frozen_string_literal: true
class RailsNgController < ApplicationController
# before_action :authenticate_user!
layout "rails_ng"
def index
@images = {
instagram: path_to_asset('landing/server-instagram'),
twitter: path_to_asset('landing/server-twitter'),
medium: path_to_asset('landing/server-medium'),
logo: path_to_asset('landing/iquest-logo.png'),
advert: path_to_asset('landing/RailsNigeria.png'),
railslogo: path_to_asset('landing/rails-small.png')
}
end
private
def path_to_asset(asset)
ApplicationController.helpers.asset_path(asset)
end
end
config/application.rb - this file is configured to make rails to pick up saas fonts from assets pipeline.
require_relative 'boot'
require 'rails/all'
Bundler.require(*Rails.groups)
module Chatty
class Application < Rails::Application
config.load_defaults 5.1
config.assets.paths << Rails.root.join("app", "assets", "fonts")
if Rails.configuration.respond_to?(:sass)
Rails.configuration.sass.tap do |config|
config.preferred_syntax = :sass
end
end
end
end
My results in Google Chrome console:
[SERVER] RENDERED RailsNgOne to dom node with id: RailsNgOne-react-component-8a9e89f0-3a29-4e82-9def-ed0dd15b091d with railsContext: {"inMailer":false,"i18nLocale":"en","i18nDefaultLocale":"en","href":"http://localhost:3000/","location":"/","scheme":"http","host":"localhost","port":3000,"pathname":"/","search":null,"httpAcceptLanguage":"en-US,en;q=0.8","serverSide":true}
createReactElement.js?46c3:40 RENDERED RailsNgOne to dom node with id: RailsNgOne-react-component-8a9e89f0-3a29-4e82-9def-ed0dd15b091d with props, railsContext: Objectadvert: "/assets/landing/RailsNigeria-19e84826196ea914bb17b5ba0d19b1a433147f64930a2d56eee88966b6fd6932.png"instagram: "/assets/landing/server-instagram-8309aeb4b134643b3849b1de08841274b887d7151c5696335cd8b22df607a4f9.png"logo: "/assets/landing/iquest-logo-8933b1ebd899e105fab35298969a54ded275285b751dc56f0314e5fe39945edd.png"medium: "/assets/landing/server-medium-7f29c9056261f92fb263996e317bd5a923a97d3867663c2f09c838e8cef2eda6.png"railslogo: "/assets/landing/rails-small-8a536281b93bba16489868c3387a2855c422e7e9f0b74e8bc09f89ea8c93738b.png"twitter: "/assets/landing/server-twitter-3f8241068c8426a8e17df940a1fd6706dacf7eca06623f5e0f440c0879a2c4d7.png"__proto__: Object Objecthost: "localhost"href: "http://localhost:3000/"httpAcceptLanguage: "en-US,en;q=0.8"i18nDefaultLocale: "en"i18nLocale: "en"inMailer: falselocation: "/"pathname: "/"port: 3000scheme: "http"search: nullserverSide: false__proto__: Object
The isssue with react router is inability to pass props from server side. This with-react-router-screenshot show that image props from server could not be passed. This was was due to RailsNg component passed through the router. I don't have enough reputation to post more than two links. But without RailsNg component passed through react router, image props render from server side.
Your help is highly appreciated. Thanks.