Server Side Rendering with Redux and React-Server
The most common use case for server-side rendering is to handle the initial render when a user (or search engine crawler) first requests our app. When the server receives the request, it renders the required component(s) into an HTML string, and then sends it as a response to the client. From that point on, the client takes over rendering duties.
To make it clear, SSR includes the following points:
- It happens at the first request
- The server renders required components into string and sends it to the client
- The following rendering duty is on the client.
Orginally, server-side MVC frameworks like Django and RoR render all the parts of web pages through templates. They have the following drawbacks:
- Long response time. Usually, the server needs to retrieve all the needed data first, renders the whole page into HTML string and then sends the fully-fledged page to the client. Too much work needs to do before the server sends the first byte of HTML page.
- Data requests on the client are more time-consuming compared with those triggered in the server side. Usually, it’s faster to get all data packed in the server due to the data locality, and there’re also contraints on concurrent request number in the browser.
With Redux, it’s easy to implement SSR. The basic idea is that the server assembles the basic store, obtain the initial state from it and send the state to the client along with the rendered HTML string. The client will recreate the store with the received state and take over the rendering job after that. Let’s see an example to make things clear.
Assuming there’s a page with three parts, i.e, head, body and footer, and each part has to get a color propery to render from an API invocation. With Redux, we need to construct the initial store:
configureStore is just a helper function to create a store from a
Since we create the initial store, we can obtain the the HTML string with React’s
App contains a
Body and a
Then, we send the initial state with HTML string to the client:
We send the initial state to the client by setting a global variable
__PRELOADED_STATE__, the client will restore state from it:
You can see that the logic is the same by using the helper
configureStore. Then, the client will re-render the page and compare the checksum to see whether it’s the same with the markup rendered at the server side (usually it should be identical). After that, the client will take over all the rendering work.
The source code can be found at my github, play around with it to better understand Redux SSR.
There’re still something not so good of Redux SSR just mentionded above. We create three
Promise objects to get the initial data, and only start rendering the page after all of them are solved, which is quite time-consuming. Ideally, if the color of the head is retrieved, the server should render the head and send it the client to make it inteactive so that the user will not wait too long. React-Server is born for that.
RootComponent of React-Server has a
when property, and you can pass a
Promise object to it. When the
Promise object gets resolved, the server will render the component and send it to the client. Re-written the app with React-Server looks like the following:
Under the hood, each time the server parses a
RootComponent, when the data is ready (
when promise get resolved) the server will send it to the client. There is one special tag
<TheFold>, which is used to specify all the components above the fold. Once the server sees it, it will send an additional
<script> tag to the client and runtime engine in the client side will enable the event listeners on the components to make it interactive. After that, each
RootComponent will come along with a
<script> tag to make it interactive.
There is another trick of React-Server. To be isomorphic, it adds a cache layer of SuperAgent. The same codes run on both server side and client side, and once the server gets the data, the data will be cached and the client will obtain the data directly from the cache without triggering a network request.
The source code is also available at my github, you can compare it with the previous one.
This post introduced server side rendering and discussed its benifits. Two possible implementations has been given, the one using pure Redux has longer first-byte latency compared with