Frontend Development 10 min read

Implementing Isomorphic ReactJS Server-Side Rendering with Redux and React Router

The article details how to set up isomorphic ReactJS server‑side rendering using ReactDOMServer, Redux for shared state, and React Router for universal routing, covering data fetching, Webpack builds for client and Node, code‑splitting, and performance trade‑offs such as CPU overhead and caching strategies.

Tencent Music Tech Team
Tencent Music Tech Team
Tencent Music Tech Team
Implementing Isomorphic ReactJS Server-Side Rendering with Redux and React Router

This article shares practical experience of integrating ReactJS with server‑side isomorphic rendering in a project. It explains what isomorphic (or universal) rendering means: a single component or logic written once can run both on the client (browser) and on the server (Node.js), allowing the same codebase to generate HTML on the server and hydrate on the client.

React Server Rendering is achieved via the ReactDOMServer API, especially renderToString() , which converts a component tree into an HTML string. The generated HTML is sent directly to the client, so the first paint is visible without waiting for JavaScript execution. On the client, React still renders in memory and performs a DOM diff against the server‑generated markup, reducing first‑paint DOM operations.

During server rendering, component lifecycle methods differ: only componentWillMount runs because there is no mounting phase. Therefore data must be fetched before rendering, often by placing data‑fetching logic in a static method on the component class and invoking it on the server before rendering.

Redux as the Data Layer provides a single store that can be populated on the server, serialized to JSON, and used to initialize the client store. This makes state sharing straightforward.

React Router is used for routing. The same route configuration works on both sides; on the server the current location is matched to obtain renderProps , then the appropriate component tree is rendered. The article notes pitfalls such as handling redirects without extra 302 requests, avoiding conflicts between code‑splitting (on‑demand loading) and server‑side rendering, and ensuring client and server routes stay consistent (e.g., avoiding hash‑based routing on the server).

Build considerations include using Webpack to bundle both client and server code. The server build targets node with libraryTarget: "commonjs2" . Shared modules can be written in CommonJS or ES6, and Webpack’s externals can exclude native Node modules. Templates are shared: the client build produces a static HTML page, while the server build generates a template function (using ES6 template literals) that injects the rendered markup and state.

On‑demand loading is implemented with require.ensure (or dynamic import() ) so that only needed chunks are loaded at runtime.

Platform differences (e.g., AJAX on the client vs. http.request on the server) can be abstracted via aliasing or Webpack’s DefinePlugin to inject environment‑specific code.

The article concludes with performance observations: server‑side rendering adds significant CPU overhead. In a benchmark on an 8‑core, 16 GB server, TPS dropped from ~2400 (no rendering) to ~900 when renderToString() was used, saturating the CPU. Recommendations include reducing the complexity of first‑screen components, minimizing calculations inside render() , and exploring caching strategies or stream‑based rendering (as discussed in Vue 2.0 and some React proposals).

PerformanceReduxReactWebpackserver-side renderingIsomorphicReact Router
Tencent Music Tech Team
Written by

Tencent Music Tech Team

Public account of Tencent Music's development team, focusing on technology sharing and communication.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.