Background
I am using next.js for server side rendering and react.js for client side.
Goal
Want to do conditional rendering on the basis of window size in server side. Like for 200px width render A component and for 400px width render B component.
Problem
In server side, we have no access to the window object and we have no idea about the device our client is using. So AFAIK we cant do conditional rendering on server side.
Thoughts
I have thought of some solutions, but don't know is it possible or not -
1. Send the device info or window object as json with the http request.
2. Don't render the conditional components in server side and re-render (hydrate) them on client side.
But I don't know what is the best practice and what is more efficient than other. New suggestions are also welcome.
Consider using next approach:
On server side you can predict device type by parsing user-agent
with help of mobile-detect package and pass expected values to
an isomorphic HOC created on top of react-sizes which allows to
setup "predicted" screen sizes to work on server side.
Wrap your conditional logic with appropriate to your business logic
structures with adaptive HOC you've created
...
Profit
Be aware of at least next cases you should take care of:
Narrow screens of desktop user-agents will be rendered as for
desktop, but might start re-rendering on client side, as MatchMedia
gonna do its work on client
Any caching layer should include parsed device type into cache key
so you will not cache potentially broken layout.
I had a few places with these conditions.
At the end I decided to only render conditional component on the client side as least problematic solution with smallest overhead.
Other solutions:
If its a component with an important SEO content and you need to render it (make it look a bit better if its rendered on a wrong size till react rerenders component depending on the screen size). Bare in mind this approach can introduce some bugs during rehydratation as react sometimes duplicates div's. You can set a new key for a compont to fix it.
You can also use css for hidding content.
You can know if the device is a mobile or not by using this piece of code in your server.js
app.get('*', (req, res) => {
var ua = req.header('user-agent');
if (/mobile/i.test(ua)) {
//mobile code
} else {
// desktop code
}
});
and you can pass this boolean in react and use it
Related
I have conditional renders in my DOM that only render when the mobile breakpoint has been met. However my webpage still displays or doesn't display those conditional components when they shouldn't be displayed or the page gets completely distorted.
According to this blog:
The server doesn’t recognize the window neither document. This means that the device, in other words, cannot detect obligatory properties (such as the viewport dimensions of the client) - thereby it needs to infer them someway, which means, a pretty limited and non-accurate way to respond.
For instance, imagine we’ve an application that uses matchMedia
(which, as you probably know, is a Web API that arrives on top of
thewindow) to render components conditionally based on the viewport
dimensions. How would you expect the server to render the markup
without thewindow, and even if it’s hypothetically polyfilled somehow,
what about the dimensions? How would it respond once the initial
render contains a responsive component that conditionally affected by
a breakpoint?
Put it simply - this might cause the server to render our application
incorrectly, which eventually, leads to partial hydration that patches
the mismatches (namely potential bugs?).
In other words, since its server-side, it does not have access to the dimensions of your screen. Thus the most robust method is to simply use css media queries to conditionally render components.
I am slightly confused about the merits of ssr and code splitting and and code splitting done solely on the client.
My thoughts are that server rendering the page first will lead to a better experience without all the javascript having to be parsed and then server rendered.
I am confused how code splitting fits into the ssr model, is it that ssr renders the first hit and then code splitting is done thereafter on the client?
React.Lazy makes a point of saying react.client is all done on the client. How would it differ from code splitting on the server. Is that if you go to a specific route then you retrieve that chunk for the first render?
I understand React.Lazy is all done on the clientside and they have made a real point of saying that. How would it differ if it was done on the server.
Is there any real benefit to ssr with code splitting. Does it not just add complexity?
tl;dr
Depending on your usecase you may use only SSR, only code-splitting or combine both as needed.
Merits of SSR
Better SEO since search bots have markup to work with (and not necessarily dependent on executing javascript) for indexing.
Faster initial render since markup is sent from the server, the browser doesn't has to wait on executing the javascript to render it. (Although the markup will still lack interactivity till react is hydrated client side).
Deliver critical CSS first. The critical CSS for the initial page render can be in-lined, better UX since the loaded markup will already have styles ready.
Simpler route splitting. SSR imo makes it simpler to reason about route splitting your application. For example, you may have different pages for /about and /home which you can route split to reduce bundle size (and preload other routes on client side if needed).
Combining code splitting your components and SSR
It might not be necessary to server render your entire page. For example, consider your homepage (which you wish to server render) includes a Chat component so users can directly ask you questions.
If this component is big you may decide to not server render it so the user can get the most important bits of the page first. This would reduce your initial page load by code splitting this component in your homepage component.
When the browser has parsed the markup it would load your Chat component after the main bundle. This way you could identify and keep your bundle sizes in check.
Only using code splitting
This is a perfectly fine way to build your application imo if you are not interested in the benefits of SSR.
For example, if your application is a user dashboard for authenticated users, it might be better to not worry about SSR at all and just code split your application. Also note that server rendering your application will take more time to send response on server (instead of plain REST APIs) since the markup has to be generated.
Coming to your questions:
I am confused how code splitting fits into the ssr model, is it that ssr renders the first hit and then code splitting is done thereafter on the client?
Yes, kinda. The browser receives the initial load from server, after that client takes care of loading the necessary bits. Now, you may decide to preload your components server side and send everything as well (please check react-loadable which I mention at the end of this answer).
How would it differ from code splitting on the server. Is that if you go to a specific route then you retrieve that chunk for the first render?
lazy is just a cleaner API with support for Suspense for code-splitting. Ideally, when loading a route for the first time you would server render the initial markup and then let the client take care of loading next bits and routing. Imo Next.js does this really well.
How would it differ if it was done on the server.
You may preload all your components or only the necessary bits. Please check the Combining code splitting your components and SSR section.
Is there any real benefit to ssr with code splitting. Does it not just add complexity?
Everything has its own trade-off here imo. As I mention in the Only using code splitting section, its perfectly fine to just use code-splitting if your use case doesn't require the merits of SSR.
Note
Currently lazy (in React v16.6.1) doesn't support SSR completely. You might want to check out react-loadable to handle the cases where you wish to preload components server side.
Server-side rendering
Useful for SEO matters pages
When the page is requested, the server processes the request and builds the final HTML page which is then delivered to the client.
This approach favors SEO matter pages since the final content is available in the first request, therefore search engines are able to index it.
Code-splitting
Useful for pages where content is loaded at different times
If your entire website uses too many resources at different load times, code-splitting is the go-to technique for performance optimization. Instead of having all the resources load with the first request, you delay the loading until the resource is needed.
Implementing both together
Given the case that you have a website with lots of resources and you want to render the entire page requested before handling it to the client, you might want to implement both of this techniques.
React.lazy()
React.lazy() was implemented in React v16.6.0 as a new method of using the Suspense component to do code-splitting.
Note
This feature is not yet available for server-side rendering.
Suspense support will be added in a later release.
To sum up
Suspense + React.lazy() doesn't yet support server-side rendering.
Server-side rendering + code splitting allows for the client to get the requested rendered page without extra resources that aren't needed at the moment.
You are asking many questions here. In my opinion code splitting is useful for larger applications, where your built bundle is just too big for a single load. While server side rendering is useful for smaller landing page style of pages, therefore reducing the compute time in the browser.
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:"
I am building an isomorphic app with React that must support users without JS.
I am new in this technology and I have a basic doubt:
The server can store the components states to emulate what React does in the client-side?
I imagine this flow when the user dont have JS:
The user click a button and send a request to the server.
The server recovers the state of the app and makes changes in it.
The components listen this changes and are rendered again.
Is it correct?
Assuming that you're using react-router :
The server aims to initialize your state, to provide it the default minimum values necessary to make your application work while getting an url.
For example, if you have an application in which you want to display a user list, let say on /users URL, when you'll send your first request, the server will store the users in the react state.
After that first load, you'll be working on the client side using react-router, and making XHR request.
However, if you refresh your page, the process will start again : first load initializing the state and then client side navigation.
EDIT : Explanations =>
When you want to use react on the server, this means that you use a Nodejs server. The fact is that react-dom provides a method called renderToString that transform a react jsx component into standard HTML.
This aims to load the first call faster
Why ?
When you load a "big" JS application on the client, you have some delay time, the time your browser needs to download your JS bundle.
Server side rendering aims to avoid that behaviour, or at least, to gives the feeling that the app starts faster.
In no case you can only use react, even if you use your server side renders. Why ? . Because your events on buttons, or asynchronous load on client, or keypress are in JS language.
I am new to React and Redux . Although i know that React is just a view layer . But i saw a term "React can be used on server side rendering". What does this mean and how it works behind the scene with nodejs.Can anyone help me in getting clear the fact that "What is server side render in react".
The react-dom package includes a server module. This module allows you render your react application to a simple HTML string with reactDOMServer.renderTostring(). Basically a snapshot of your view for a given set of props:
https://facebook.github.io/react/docs/top-level-api.html#reactdomserver.rendertostring
Additionally this functions calculates a unique hash from the string it generated and appends it to the html. On the client side react can "pick up" the server generated HTML and use it as its "first render".
Though the client side first render and the server render need to produce the exact same output for react to pick it up on the client side. React can check this via the generated hash: The client side react will also generate a html string (without modifying the actual DOM, I think this is done only on the virtual DOM). Now it can also calculate a hash from its virtual DOM and compare it with the server rendered one. If they match, no rendering needs be done. If they don't, the client side react will throw away the server generated DOM and replace it with its version (and print out an error/warning).
In combination with redux this means in addition to rendering the HTML you need to pass down the state of your store (store.getState()) to the client. The client can then use this serialized state as an initial state when creating its instance of the redux store. This will lead to both renders (client + server) to match up.
If you don't need the client side to do anything and just want to create static markup on the server side, react-dom offers a renderToStaticMarkup() function:
https://facebook.github.io/react/docs/top-level-api.html#reactdomserver.rendertostaticmarkup