Skip to content

Instantly share code, notes, and snippets.

@koistya
Last active September 15, 2023 07:32
Show Gist options
  • Star 90 You must be signed in to star a gist
  • Fork 12 You must be signed in to fork a gist
  • Save koistya/24715d295fbf710d1e24 to your computer and use it in GitHub Desktop.
Save koistya/24715d295fbf710d1e24 to your computer and use it in GitHub Desktop.
Server-side Rendering (SSR) for ReactJS / Flux Applications. Setting document.title

Files

The basic structure of a React+Flux application (see other examples)

 - /src/actions/AppActions.js     - Action creators (Flux)
 - /src/components/Application.js - The top-level React component
 - /src/constants/ActionTypes.js  - Action types (Flux)
 - /src/core/Dispatcher.js        - Dispatcher (Flux)
 - /src/stores/AppStore.js        - The main store (Flux)
 - /src/app.js                    - Client-side startup script
 - /src/server.js                 - Server-side startup script

The Top-level React Component

// src/components/Application.js

var React = require('react');

var Application = React.createClass({

  propTypes: {
    path: React.PropTypes.string.isRequired,
    onSetTitle: React.PropTypes.func.isRequired
  },

  render() {
    var page = AppStore.getPage(this.props.path);
    this.props.onSetTitle(page.title);
    
    return (
      <div className="container">
        <h1>{page.title}</h1>
        <div>{page.content}</div>
      </div>
    );
  }
});

module.exports = Application;

Client-side Startup Script (aka Bootstrap)

// src/app.js

var React = require('react');
var Dispatcher = require('./core/Dispatcher');
var Application = require('./components/Application');

var app = React.createElement(Application, {
  path: window.location.pathname,
  onSetTitle: (title) => document.title = title
}));

app = React.render(app, document.body);

Dispatcher.register((payload) => {
  if (payload.action.actionType === ActionTypes.CHANGE_LOCATION) {
    app.setProps({path: payload.action.path});
  }
});

Server-side Startup Script (Node.js/Express)

// src/server.js

var _ = require('lodash');
var express = require('express');
var React = require('react');

// The top-level React component + HTML template for it
var Application = React.createFactory(require('./components/Application'));
var template = fs.readFileSync(path.join(__dirname, 'index.html'), 'utf8');

var server = express();

server.set('port', (process.env.PORT || 5000));

// Server-side rendering (SSR)
server.get('*', function(req, res) {
  var data = {};
  var component = Application({
    path: req.path,
    onSetTitle: (title) => data.title = title,
    onPageNotFound: () => res.status(404)
  });
  data.body = React.renderToString(component);
  var html = _.template(template, data);
  res.send(html);
});

server.listen(server.get('port'), function() {
  console.log('HTTP server is running at http://localhost:' + server.get('port'));
});

HTML Template for Server-side Rendering

// src/index.html

<!doctype html>
<html class="no-js" lang="">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title><%- title %></title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="css/app.css">
  </head>
  <body>
    <!--[if lt IE 8]>
      <p class="browsehappy">
        You are using an <strong>outdated</strong> browser.
        Please <a href="http://browsehappy.com/">upgrade your browser</a>
        to improve your experience.
      </p>
    <![endif]-->
    <%= body %>
    <script src="app.js"></script>
  </body>
</html>

Example

@igorgolovanov
Copy link

igorgolovanov commented Nov 17, 2016

@frank-dspeed
Copy link

@philipgiuliani, @cameronroe, @jeremyeast, @MelkorNemesis, @aayler, @bigdestroyer, @Laskos, @perpaer (@imrvelj), @Kaveckas, @evidanary, @dkoleary88 @louwers @komocode @wzup @boyney123 @penakamaayo @NazarYablonskiy @michaelost, @abaoaqus, @buscando, @RusinovAnton @NobleGestures, @lubbertdas, @aight8, @Maxpain177, @rcolepeterson, @maxbook, @o-shabashov, @golovanov

I want to Answer that Question There is More than one DOM in Reality.
Shadow DOM, browser DOM, Other Virtual DOM's,

So first of all the ServerSide Renders and throws that HTML after that the frontend will render also but in a Virtual DOM and it will Only render Objects that are not in the browser DOM and will take Parts from the Browser DOM and will sync both

Keywords for that are Shadow binding, DOM Syncing, and so on bind and attach of DOM Elements.

You can think about a DOM like a normal JAVASCRIPT Object :) so we can easy loop over them.

Hope that makes sense and helped you all to understand.

@xuezhma
Copy link

xuezhma commented Aug 29, 2017

@quentinbt
Copy link

@digitalashes
Copy link

@Mach12
Copy link

Mach12 commented Mar 5, 2018

@rohail-kalyar-pakwheels
Copy link

All,
Hopefully, this approach can help you.

https://fluxible.io/blog/2014-11-06-bringing-flux-to-the-server.html

@ondrek
Copy link

ondrek commented Jan 28, 2021

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment