ReactJS server-side rendering vs client-side rendering - javascript

I just have began to study ReactJS and found that it gives you 2 ways to render pages: server-side and client-side. But, I can't understand how to use it together. Is it 2 separate ways to build the application, or can they be used together?
If we can use it together, how to do it - do we need to duplicate the same elements on the server side and client side? Or, can we just build the static parts of our application on the server, and the dynamic parts on the client side, without any connection to the server side that was already pre-rendered?

For a given website / web-application, you can use react either client-side, server-side or both.
Client-Side
Over here, you are completely running ReactJS on the browser. This is the simplest setup and includes most examples (including the ones on http://reactjs.org). The initial HTML rendered by the server is a placeholder and the entire UI is rendered in the browser once all your scripts load.
Server-Side
Think of ReactJS as a server-side templating engine here (like jade, handlebars, etc...). The HTML rendered by the server contains the UI as it should be and you do not wait for any scripts to load. Your page can be indexed by a search engine (if one does not execute any javascript).
Since the UI is rendered on the server, none of your event handlers would work and there's no interactivity (you have a static page).
Both
Here, the initial render is on the server. Hence, the HTML received by the browser has the UI as it should be. Once the scripts are loaded, the virtual DOM is re-rendered once again to set up your components' event handlers.
Over here, you need to make sure that you re-render the exact same virtual DOM (root ReactJS component) with the same props that you used to render on the server. Otherwise, ReactJS will complain that the server-side and client-side virtual DOMs don't match.
Since ReactJS diffs the virtual DOMs between re-renders, the real DOM is not mutated. Only the event handlers are bound to the real DOM elements.

Image source: Walmart Labs Engineering Blog
NB: SSR (Server Side Rendering), CSR (Client Side Rendering).
The main difference being that with SSR, the servers response to the clients browser, includes the HTML of the page to be rendered.
It is also important to note that although, with SSR, the page renders quicker. The page will not be ready for user interaction until JS files have been downloaded and the browser has executed React.
One downside is that the SSR TTFB (Time to First Byte) can be slightly longer. Understandably so, because the server takes some time creating the HTML document, which in turn increases the servers response size.

I was actually wondering the same researching quite a bit and while the answer you are looking for was given in the comments but I feel it should be more prominent hence I'm writing this post (which I will update once I can come up with a better way as I find the solution architecturally at least questionable).
You would need to write your components with both ways in mind thus basically putting if switches everywhere to determine whether you are on the client or the server and then do either as DB query (or whatever appropriate on the server) or a REST call (on the client). Then you would have to write endpoints which generate your data and expose it to the client and there you go.
Again, happy to learn about a cleaner solution.

Is it 2 separate ways to build the application, or can they be used together?
They can be used together.
If we can use it together, how to do it - do we need to duplicate the
same elements on the server side and client side? Or, can we just
build the static parts of our application on the server, and the
dynamic parts on the client side, without any connection to the server
side that was already pre-rendered?
It's better to have the same layout being rendered to avoid reflow and repaint operations, less flicker / blinks, your page will be smoother. However, it's not a limitation. You could very well cache the SSR html (something Electrode does to cut down response time) / send a static html which gets overwritten by the CSR (client side render).
If you're just starting with SSR, I would recommend start simple, SSR can get very complex very quickly. To build html on the server means losing access to objects like window, document (you have these on the client), losing ability to incorporate async operations (out of the box), and generally lots of code edits to get your code SSR compatible (since you'll have to use webpack to pack your bundle.js). Things like CSS imports, require vs import suddenly start biting you (this is not the case in default React app without webpack).
The general pattern of SSR looks like this. An Express server serving requests:
const app = Express();
const port = 8092;
// This is fired every time the server side receives a request
app.use(handleRender);
function handleRender(req, res) {
const fullUrl = req.protocol + '://' + req.get('host') + req.originalUrl;
console.log('fullUrl: ', fullUrl);
console.log('req.url: ', req.url);
// Create a new Redux store instance
const store = createStore(reducerFn);
const urlToRender = req.url;
// Render the component to a string
const html = renderToString(
<Provider store={store}>
<StaticRouter location={urlToRender} context={{}}>
{routes}
</StaticRouter>
</Provider>
);
const helmet = Helmet.renderStatic();
// Grab the initial state from our Redux store
const preloadedState = store.getState();
// Send the rendered page back to the client
res.send(renderFullPage(helmet, html, preloadedState));
}
My suggestion to folks starting out with SSR would be to serve out static html. You can get the static html by running the CSR SPA app:
document.getElementById('root').innerHTML
Don't forget, the only reasons to use SSR should be:
SEO
Faster loads (I would discount this)
Hack : https://medium.com/#gagan_goku/react-and-server-side-rendering-ssr-444d8c48abfc

Related

Best way to organise back end (Node) processes and front end (Vue / Nuxt) that uses part of these processes

I have a few tiny node apps doing some basic stuff like checking things and filling my DB (triggered by CRON). In my Nuxt app I will need to use part of what is insinde these Node apps. What is the best way to organise it, do I keep them separated or do I fuse them with my Nuxt app ? Do I copy what I need from these node apps and adapt it in Nuxt, do I use the serverside middlewares to add those node apps inside my Nuxt project or do I create my Nuxt app with express and I use /server/index.js to add my node apps there in some way ?
Let's take an example. You have a node app that check very hour some data and fill a DB. In the Nuxt app you have a page showing the content of the DB but you want first to be sure that nothing new has to be added in the DB since the last hour. The code I would have to run in th every Nuxt page is the same code as the Node app (check and fill the DB). It looks a bit stupid (and hard to maintain and update) to have twice the same code at two places. But I 'm not sure how would I have this node app running every hour in my Nuxt app. Any advice would be greatly appreciated
Here is a control flow that may help your thinking about designing this CRON microservice. There are many ways to do this, and this may not be the best approach, but I think it will work for your use case.
Have a services directory in your server (can also be called middleware).
Include a cron.js file that contains the logic for the task runner.
Within cron.js, issue a scheduled response from node to Vue, such as a JSON keyword like res.JSON({message: 'checkNewData'}). This will be something called a "server sent event". A server sent event is simply an event that happens autonomously on a defined schedule within node environment.
In Vue, at the root level App.vue, use the created() hook to register an event listener that will listen for the server sent "checkNewData" JSON object. When this event listener hears the JSON response, it should trigger Vue to check the appropriate component, package up any new data, and send it down to the DB in a post or put http call, depending on whether you're adding new data, or replacing the old with the new.
This configuration would give you a closed-loop system for automatic updates. The next challenge would be making this operation client-specific, but that is something to worry about once you got this working. Again, others may have a different approach to this, but this is how I would handle the flow.

rendering js server side

I have a webapp that displays a lot of interactive JS data tables and graphs in a single page (about 50-60). The page rendering required takes a lot of time (Chrome WebTools show about 20-25 seconds in the "Rendering" State from ajax response to completion) since each interactive element is a standalone "widget".
Because the types and structure of the tables/graphs is mostly constant and only the data varies, I think it's very inefficient to have the client render them each time. It would be better to send the client a rendered page and only populate the data where needed.
I've read about Headless Chrome and Puppeteer but they are NodeJS modules. I was wondering if there was a way to incorporate this server-side rendering of JS in a Python-based backend.
You can render React components server-side with python-react or with python-react-v8.
Installation:
pip install react
Usage:
from react.render import render_component
rendered = render_component(
'/path/to/component.jsx',
{
'foo': 'bar',
'woz': [1,2,3],
}
)
print(rendered)
More about the render server.

Live updating dynamic variable on HTML with Flask

I'm creating a website that scraps with BeautifulSoup4 articles from other website and gives the user the articles as an output.
The articles are being saved in a data base. Each articles gets an id.
Current relevant code part for example:
#scrap.py
id = 0
if 'article' == 'new': #clearly this is just for the example...
id = id+1
I want the user will be able to see in real-time how many articles have been collected. Current relevant HTML code part for example:
<!--index.html-->
<div id="cur_id">{{ cur_id }}</div>
I'm rendering the id with flask to the HTML page. Current relevant code part for example:
#main.py
#app.route('/')
#app.route('/templates/index.html')
def index (name=None):
cur_id = scrap.id
return render_template('index.html', name=name, cur_id=cur_id)
How can i make the <div> in the HTML to get updated in real-time every time id gets updated?
Thanks!
Flask can do nothing to change the content of an already served webpage. As soon as the HTML is created and send to the client, flask is "done". Then the browser does stuff like interpreting the HTML, interpreting javscript (and possible adding interactions to the webpage) and lots of other things. Note that the client doesn't need to do this, there are clients that only download the HTML and are done (e.g. curl/wget).
So changing content on a webpage can only happen clientside, which essentially means javascript. If we have a new value, how do we update the content? Vanillajs is relativly simple:
var new_data = "3";
cur_id = document.getElementById('cur_id');
cur_id.innerHTML = new_data;
There are lots of libraries which help you with updating content. Jquery is an often used general purpose library. There are entire libraries which only focus on how to update the UI with new content, e.g. vue, react, ember and probably lots of others. react and ember also provide a server side if I remember correctly, so if you don't want to do vanillajs vue might be worth a look. But if you only want to update a single value you can't really beat the two lines vanillajs.
In the above snippet the new value is hardcoded which isn't helpful. How do we get new values to the client? If you really want realtime information websockets are the way to go. These are somewhat new and you should check if browser compatibility is acceptable for you.
cur_id = document.getElementById('cur_id');
ws = new WebSocket("wss://echo.websocket.org")
ws.onmessage = function(event) {cur_id.innerHTML = event.data};
simulate_update = function() {ws.send(Number(cur_id.innerHTML) + 1)};
ws.onopen = function(event) {setInterval(simulate_update, 2000)};
This uses an echo websocket server to simulate the server sending new information, but ofcourse it should connect to your websocket server. Flask per default cannot use websockets, but there some plugins like flask-sockets which make this possible. The "protocol" used above is very dumb and depending on your needs you want something smarter.
There are libraries which help with writing websocket code, often with integrated protocols. I think the most often used one is socketio which can fallback to different methods to exchange data (long polling, ajax) and puts a event/RPC/pubsub framework in front as far as I remember. It should also deal with reconnecting, heartbeat and other problems which one may not initially think about. There are lots of different websocket libraries.

embedded JavaScript on the client side security

1) One way to put javascript on the client side is EJS e.g.
<h1> <%= title %> </h1>
where title is a variable.
2) Another way is to use back ticks and insert html or append etc using a library like jQuery
$('h1').html(`{obj.title}`);
3) A third way is to use react js esx, so import all the files on the client side if you are going down that route and add an variable as follows:
<div id="holder1"></diV>
var title = React.createClass({
render: function(){
return(
<h1 className="title1">{this.props.title1}<h1>
)
}
});
ReactDOM.render(<title
title1: "Hello World" />,
document.getElementById("holder1")
);
My question is how does react.js handle security so that the javascript cannot be manipulated such as a password on the client side (Not server side) and for 1-2 how can you enforce data hiding and prevent someone from changing the values. Can this only be done using server side react.js using node.
Let me clarify: How does React.js and other javascript libraries make the front end more secure... not just passwords... that can be handled with bcrypt hashes and https.
It's not entirely clear what you are asking, but as a very general rule, anything in the client can't be trusted.
Input posted to the server from the client can't be trusted, and should not be later displayed without proper precautions.
Web security is a huge topic. So I suggest you break your question down into smaller chunks and really identify what you are trying to ask.
Regarding React - it's not doing anything special around passwords. Its the responsibility of the backend service layer to protect from malicious input - there is a very real chance that a React component would send back crappy/malicious data. (not Reacts fault, nor is it the intent of React)
The only thing React has in this regard is {} vs dangerouslySetInnerHtml, but again, thats not going to protect passwords or the like.

Strategy for making React image gallery SEO-friendly

I wrote a React image gallery or slideshow. I need to make the alt text indexable by search engines, but because my server is in PHP, React.renderToString is of limited use.
The server is in PHP + MySQL. The PHP uses Smarty, a decent PHP template engine, to render the HTML. The rest of the PHP framework is my own. The Smarty template has this single ungainly line:
<script>
var GalleryData = {$gallery};
</script>
which is rendered by the PHP's controller function as follows:
return array(
'gallery' => json_encode($gallery),
);
($gallery being the result table of a MySQL query).
And my .js:
React.render(<Gallery gallery={GalleryData} />, $('.gallery').get(0));
Not the most elegant setup, but given that my server is in PHP there doesn't seem to be much of a better way to do it (?)
I did a super quick hack to fix this at first shot - I copied the rendered HTML from Firebug, and manually inserted it into a new table in the DB. I then simply render this blob of code from PHP and we're good to go on the browser.
There was one complication which is that because React components are only inserted into the DOM as they're first rendered (as I understand it), and because the gallery only shows one image slide at a time, I had to manually click through all slides once before saving the HTML code out.
Now however the alt text is editable by CMS and so I need to automate this process, or come up with a better solution.
Rewriting the server in Node.js is out of the question.
My first guess is that I need to install Node, and write a script that creates the same React component. Because the input data (including the alt text) has to come from MySQL, I have a few choices:
connect to the MySQL DB from Note, and replicate the query
create a response URL on the PHP side that returns only the JSON (putting the SQL query into a common function)
fetch the entire page in Node but extracting GalleryData will be a mess
I then have to ensure that all components are rendered into the DOM, so I can script that by manually calling the nextSlide() method as many times as there are slides (less one).
Finally I'll save the rendered DOM into the DB again (so the Node script will require a MySQL connection after all - maybe the 1st option is the best).
This whole process seems very complicated for such a basic requirement. Am I missing something?
I'm completely new to Node and the whole idea of building a DOM outside of the browser is basically new to me. I don't mind introducing Node into my architecture but it will only be to support React being used on the front-end.
Note that the website has about 15,000 pageviews a month, so massive scalability isn't a consideration - I don't use any page caching as it simply isn't needed for this volume of traffic.
I'm likely to have a few React components that need to be rendered statically like this, but maintaining a small technical overhead (e.g. maintaing a set of parallel SQL queries in Node) won't be a big problem.
Can anyone guide me here?
I think you should try rendering React components on server-side using PHP. Here is a PHP lib to do that.
But, yes, you'll basically need to use V8js from your PHP code. However, it's kind of experimental and you may need to use other around. (And this "other way around" may be using Node/Express to render your component. Here is some thoughts on how to do it.)

Categories