React - Server-rendered markup (renderToString / hydrate)

About

server-rendered markup is the dynamic possibility of server-side rendering (vs static).

The steps are:

Advantages

  • Faster page loads: The html is rendered. The page does not need to load the javascript bundle to render.
  • SEO purposes: It allow search engines to crawl your pages without Javascript.

The disadvantage is that the architecture is more complicated and you need to take into account where your code will be running (ie on the server or on the browser).

Steps

Server: Html page creation

On the server side, you can use of this two methods to generate HTML with react data attributes:

  • ReactDOMServer.renderToString(..) 1) to render a React element to its initial HTML. React will return an HTML string.
  • ReactDOMServer.renderToNodeStream(element) 2) - Returns a Readable stream



The below example shows you how to create a page on the server side with the ReactDOMServer.renderToString(..) 3) function.

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}
const App = <Welcome name="Foo" />;
  • The rendering to transform the component in reacted HTML
const  toHydrateHtml = ReactDOMServer.renderToString(App);
  • The creation of the HTML page where /static/bundle.js is the classic React bundle (see client bundle) that will start the hydratation (tree building) after loading.
const htmlPage = `
<!doctype html>
<html>
  <head>
	<title>Dynamic SSR example</title>
  </head>
  <body>
  
        <div id="root">
        
        <!-- The reacted HTML inside the root div element -->
        ${toHydrateHtml}
        
        </div>

        <!-- The classic bundle (client) that calls the building of the tree with the hydratation when loaded -->     
        <script  src="/static/bundle.js">
  </body>
</html>
`;
  • If you would be on a server, you would use it like that. Example with a Node HTTP server
// http.createServer(function (req, res) {
//       res.writeHead(200, {'Content-Type': 'text/html');
//       res.write(htmlPage);
//       res.end();
//}).listen(port);
  • In our case, we just output it to the console.
console.log(htmlPage.trim());
  • Output: The page send will look like that:

Client: Hydratation React bundle

This section shows you how to create the bundle.js file added to the pages created on the server side.

The pages will become active, or hydrated, when the JavaScript bundle has loaded.

The bundle is a classic javascript bundle but:

The client.js (start point for the bundle.js file) client would looks like (import/export statement excluded)

window.addEventListener("load", () => {
  ReactDOM.hydrate(<App />, document.getElementById('root'));
};);

Code Demo

A fully functional demo repository can be found here if you want to take a look.

Library / Tool

Next

A full server framework with own link/image/routing component React Framework - Next.js. Doc

Razzle

A framework that tries to do no more than basic server side rendering and lets you choose all other library (routing/…).

razzle (https://razzlejs.org/docs/how-it-works)

2 configs, 2 ports, 2 webpack instances, both watching and hot reloading the same filesystem, in parallel during development and a little webpack.output.publicPath magic.

Deprecated

Rendering Time

There is two moments where you can render:

  • at runtime - rendered on the server (the files are created on demand)
  • at build time - rendered at build time (a lot of static files are created)

Runtime

At runtime, means that the node server will render when an HTTP request is made.

Build time

You can render (ie create the pages) at build time which is called prerendering / snapshoting

You don't need a node server.

See Web - Prerendering / Snapshoting (Dynamic to Static Web Site Generation)

Documentation / Reference


Powered by ComboStrap