I recently started looking into SSR(Server side rendering) and I am impressed with its advantages. To name a few Load times, SEO, No javascript configuration.
However I am trying to understand if react server side rendering is worth it.
React is known for its Virtual DOM manipulations but using react with server side rendering will not give benefits of reactJs.
Can some one shed your ideas on using reactJS for server side rendering?
Using server-side rendering in React does not imply that React will not be used on client-side.
One of completely valid approaches is to start with client-side rendering only. In this case you have to setup a single HTML element in your HTML file that will become a hook for React once it loads.
Just to give you an example, let's say we have an <div id="root"></div> element in index.html file that will be served if we HTTP GET / path on our server. Initial document (in our case index.html) should also reference javascript file that includes React and our code. It can be done by adding something like <script type="text/javascript" src="/index.js"></script> just before </body> tag.
At some point while index.js is executed, ReactDOM.render() method is called (note: we are in the browser right now) - this is a moment in time when React looks for a div element with root id attached in a document. After it's found, it becomes react-root - component tree is mounted under this element and managed by React (ie. virtual DOM, event handlers, state updates).
Please note that this approach requires that at least one javascript file is fetched, parsed and executed before browser can render anything meaningful (other than an empty div) to a user. For some scenarios, this is not acceptable and this is where SSR (server-side rendering) can help.
Server-side rendering requires that you have JavaScript runtime environment available on your server. One of the popular choices is Node.js (others include for example Nashron for JVM).
In approach, you execute React on the server and use ReactDOMServer.renderToString() (or ReactDOMServer.renderToNodeStream()) method to generate HTML response that is sent to the client - instead of an almost empty response with just one placeholder div as previously, now you can send all the markup that will be generated from your component tree (important note here is that in React 16.4(+) only UNSAFE_componentWillMount lifecycle method is called on server-side). After the initial response with a document is sent to the client, browser can render the initial markup before index.js even finishes downloading. Once it does, ReactDOM.hydrate() method kicks in. Hydration is a process of using existing server-side rendered markup and "watering" it with javascript goodies like event handlers. After it's done, this component tree is now completely managed by React with all the benefits.
Please note that in SSR, exactly the same component tree is rendered on a server-side and that's then hydrated on a client-side.
Of course, React can also be used instead of templating engines as a very powerful static HTML markup generator. All you need to do is to render the markup on the server with ReactDOMServer. renderToStaticMarkup() and send it to the client. It should be noted that this approach has a significant performance impact (https://malloc.fi/performance-cost-of-server-side-rendered-react-node-js) and uses a very limited number of React features.
Related
With SSR, JavaScript must be fetched for interactivity, which is often achieved via hydration. How will this be achieved with server components?
React server components don't have state, event handlers, etc. and cannot themselves be interactive. But they can be interleaved with client components, which can be interactive.
Also - React server components still require Javascript. Even for server components, even though no bundles are sent down, they are still "hydrated" in the sense that they are turned into JSX elements and then rendered onto the page as part of the React tree.
See https://blog.plasmic.app/posts/how-react-server-components-work/ for a complete look:
Why invent a whole new wire format? The goal on the client is to reconstruct the React element tree. It is much easier to accomplish this from this format than from html, where we’d have to parse the HTML to create the React elements. Note that the reconstruction of the React element tree is important, as this allows us to merge subsequent changes to the React tree with minimal commits to the DOM.
I was trying to understand what's the difference between ReactDOMServer.renderToString() and ReactDOMServer.renderToStaticMarkup() on React 16.8.6.
This is what I understood:
renderToStaticMarkup() is used on the server side when you just want to render the markup and don't want to hydrate it on the client side. (https://reactjs.org/docs/react-dom-server.html#rendertostaticmarkup)
renderToString() is used on the server side when you want to use the ReactDOM.hydrate() function to hydrate the application on the client side. (https://reactjs.org/docs/react-dom-server.html#rendertostring)
So, if I'm right, the only difference between this two methods is that renderToString() adds the data-reactroot on the main element of the application. React reinforces this on the renderToStaticMarkup() documentation:
Similar to renderToString, except this doesn’t create extra DOM
attributes that React uses internally, such as data-reactroot. This is
useful if you want to use React as a simple static page generator, as
stripping away the extra attributes can save some bytes.
If you plan to use React on the client to make the markup interactive,
do not use this method. Instead, use renderToString on the server and
ReactDOM.hydrate() on the client.
But, I was reading this issue on React's repository where Dan Abramov said:
Instead, use hydrate() to explicitly tell React to hydrate existing
HTML. Then it won't depend on whether data-reactroot exists or not.
And:
...The suggested migration path is to use ReactDOM.hydrate() which
completely sidesteps the problem because it doesn't rely on the
data-reactroot attribute.
So, my question is: Is data-reactroot relevant to the hydrate function in React or is the documentation wrong?
Understanding this will be really helpful to fix a bug I'm having while hydration.
I'm using a custom tool similar to react-snap to create a snapshot of my app at build time, as recommended in the create-react-app docs. This generates a static server-rendered version, which I can deploy behind nginx without running react on the server. This works fine.
I'm also using code-splitting to lazily load some components to reduce the initial JS payload. (I use react-loadable, but I'm willing to change that if needed.) It works fine when creating the snapshot, and the HTML is generated correctly, which the user receives correctly, and everything is displayed fully server-rendered without even downloading any JS yet. This is great.
However, during rehydration on the client, the import(...) call for the async loaded component hasn't yet been fired. Meanwhile, the DOM already has the stuff that has to be rendered, from the snapshot.
In this scenario, is there a way to prevent the initial render of a component during mounting, since I already have the content in the DOM?
Also, is it possible to have react's hydration logic run after the import is complete, so that I can prevent any flicker even after the import is complete?
If it matters, the lazy-loaded components are infrequently used routes, managed by react-router.
I am working on one react application.
My requirements are :-
1) First two pages should be rendered always from server side.
2) Rest pages should be client side rendered.
For example :-
http://foo.com and http://foo.com/about I want to rendered always from server side.
http://foo.com/FAQ, http://foo.com/contact I want to render from client side.
what is the right way to achieve this?
You should use ReactDOMServer and specificly renderToString() method.
ReactDOMServer.renderToString(element)
Render a React element to its
initial HTML. This should only be used on the server. React will
return an HTML string. You can use this method to generate HTML on the
server and send the markup down on the initial request for faster page
loads and to allow search engines to crawl your pages for SEO
purposes.
If you call ReactDOM.render() on a node that already has this
server-rendered markup, React will preserve it and only attach event
handlers, allowing you to have a very performant first-load
experience.
I created server side rendering with approach described in redux's official site, everything is great, but on client side it rendering components again, and this is not good I think. I am passing same state from server to window.__STATE__ variable and passing this to my client side createStore method as initial state, but it rerendering again.
Also please write in comments which part of code is needed to you, if so.
I am not providing since it is very similar to official page instructions code and there is no errors, just issue with rerendering, but as I understand it is not connecting to virtual DOM.
Please help me find valid way for handling this task.
Take a look at this example from the ReactGo project: https://github.com/reactGo/reactGo/blob/master/app/client.jsx#L22
They use a function onUpdate that has the conditional
if (window.__INITIAL_STATE__ !== null) {
window.__INITIAL_STATE__ = null;
return;
}
which prevents a duplicate fetches if __INITIAL_STATE__ is already defined. Your components rerendering may have something to do with the duplicate fetching.
Perhaps I am not understanding what you mean by re-rendering, but it is supposed to "re-render" on the client again. The way isomorphic works is that it renders the HTML on the server, and then the payload includes the initial state as well has the HTML markup - this way the browser "appears" to have faster page load times - since the UI is rendered even before the script is executed. Now once the HTML parsed and the script runs, React internally builds the virtual DOM and then compares it to the server generated DOM and wires up event listeners etc. It does not however, do a full re-render in that no new DOM elements should be created. If for any reason the client run of your React render results in a virtual DOM that is different from the generated server DOM, React will give you a warning.
"Warning: React attempted to reuse markup in a container but the
checksum was invalid. This generally means that you are using server
rendering and the markup generated on the server was not what the
client was expecting. React injected new markup to compensate which
works but you have lost many of the benefits of server rendering.
Instead, figure out why the markup being generated is different on the
client or server:"