React.js Serverside rendering and Event Handlers
Asked Answered
P

3

27

I am learning to use react.js and have some issues to use the event handlers. The final question would be: Is it possible to use server side rendering and send event handlers to the client automaticly?

Here is my example: I have an index.jsx which I render server side and send to the client

var React = require("react");
var DefaultLayout = require("./layout/default");

var LikeButton = React.createClass({
  getInitialState: function() {
    return {liked: false}; 
  }, 
  handleClick: function(event) {
    this.setState({liked: !this.state.liked});
  }, 
  render: function() {
    var text = this.state.liked ? 'like' : 'haven\'t liked';
    return (
      <p onClick={this.handleClick}>
        You {text} this. Click to toggle.
      </p>
    );
  } 
});

var IndexComponent = React.createClass({
   render: function(){
       return (
           <DefaultLayout title={this.props.name}>
                <div>
                        <h1>React Test</h1>
                </div>

                <div id="testButton">
                    <LikeButton/>
                </div> 

                <script type="text/babel" src="/js/react.js"></script>
           </DefaultLayout>
       )
   }   
});

But the "Like Button" does not have any interaction. To make it do something on click I have to add this code client side.

var LikeButton = React.createClass({
  getInitialState: function() {
    return {liked: false};
  },
  handleClick: function(event) {
    this.setState({liked: !this.state.liked});
  },
  render: function() {
    var text = this.state.liked ? 'like' : 'haven\'t liked';
    return (
      <p onClick={this.handleClick}>
        You {text} this. Click to toggle.
      </p>
    );
  }
});

ReactDOM.render(
  <LikeButton />,
  document.getElementById('testButton')
);

I only started out with react.js and maybe I am just missing some major concept here. But why does react.js not just create the code (which I now have to add manually to the client) when rendering the page server side? Like this, I have redundant code and it feels like this will be a mess in larger applications. At least react.js is smart enough to not draw two LikeButtons but to "bind" the one created server side to the client side component.

Patsy answered 26/3, 2016 at 8:42 Comment(3)
This is unrelated to your question but I believe you're supposed to bind the handleClick function before passing it onto the onClick or else it doesn't have the correct context of this. (But I'm not sure why you wouldn't get error when you click the button because it should throw an error when calling this.setState)Cinque
@ktruong binding is not required when using React.createClass. it auto binds.Lophophore
@jeffpc1993 Ohh thanks for pointing that out!Cinque
R
29

For a client side interactive React app, you need to render the app client side too. Usually this code is identical to the code you run on the server, so there is no redundant code. It's just the same code. You may ask yourself if rendering on both client and server might be overkill, but from a performance and SEO point of view it makes perfect sense.

ReactDOMServer.renderToString(<MyApp foo={bar} />) basically just renders a string with markup. There is no javascript or any magic going on there. Just plain old HTML. However, the rendered markup has lots of React ID attributes that are later used on the client to generate the initial Virtual DOM and attach events.

When you render your application again on the client, on the same DOM element in which your server side rendered markup was injected on the server, React doesn't need to redraw the entire application. It just creates a new Virtual DOM tree, diffs it with the initial Virtual DOM tree, and does the necessary DOM operations, if any. This concept of the virtual DOM is what makes React so fast in the first place. In the same process, any event listeners you have defined in your application will be attached to the already rendered markup.

All of this happens really fast. And you have the benefit of a server side rendered page (that can be cached on the server, using Varnish or something similar) that search engines will crawl, users don't need to wait for anything to see the initial render, and the page basically works for users who have disabled javascript.

Rosenfeld answered 26/3, 2016 at 11:36 Comment(1)
Thanks for your answer. Do you know good article to use React with Varnish?Tercentenary
L
40

This behaviour is because of what exactly server side rendering is. Firstly you will have to run the exact same code both on client side and server side. This is what is called an isomorphic application. One that runs both on server and client.
So, on doing ReactDOM.renderToString(<Component>) only the HTML is rendered as a string. The render method of your component is evaluated and the HTML required for initial rendering is generated.
When the same code is run on client, react looks up the HTML rendered and attaches JS at required places. React is smart this way, it doesn't re-render everything again at client side. Just evaluates the code and identifies where all to attach the code based on react-id each DOM element is given. (You'll react-id if you inspect element any react app)

Now one might ask what is the benefit of rendering the same thing twice?
and the answer is perceived loading time by the user. And also some minimal viewing for users who disabled JS.

Client rendered application
This is how a solely client rendered application works. (client rendered React application too)

client rendered app

The User will only see content after all skeleton HTML, JS bundles(which are often pretty big), and data is fetched and evaluated. Which means the user will often have to stare at a spinner or loading screen for a while until everything loads.

Isomorphic application (runs both on client and server)
How an Isomorphic application works,
server rendered app
In this case the server generates the full HTML by evaluating your component. And the user will see content immediately as soon as the HTML is downloaded. Although the app will only function fully once the JS bundles are also downloaded and evaluated. So the JS has to run on both sides
Thus the user sees content much faster than before. Hence the huge decrease in perceived loading time.

Lophophore answered 26/3, 2016 at 11:58 Comment(1)
I did mark @Rosenfeld answer as correct since it answeres my question and was earlier posted. But still a big thank you to your effort to answer my question. It also helped me a lot to get a better understanding of how react.js works and what concept it follows!Patsy
R
29

For a client side interactive React app, you need to render the app client side too. Usually this code is identical to the code you run on the server, so there is no redundant code. It's just the same code. You may ask yourself if rendering on both client and server might be overkill, but from a performance and SEO point of view it makes perfect sense.

ReactDOMServer.renderToString(<MyApp foo={bar} />) basically just renders a string with markup. There is no javascript or any magic going on there. Just plain old HTML. However, the rendered markup has lots of React ID attributes that are later used on the client to generate the initial Virtual DOM and attach events.

When you render your application again on the client, on the same DOM element in which your server side rendered markup was injected on the server, React doesn't need to redraw the entire application. It just creates a new Virtual DOM tree, diffs it with the initial Virtual DOM tree, and does the necessary DOM operations, if any. This concept of the virtual DOM is what makes React so fast in the first place. In the same process, any event listeners you have defined in your application will be attached to the already rendered markup.

All of this happens really fast. And you have the benefit of a server side rendered page (that can be cached on the server, using Varnish or something similar) that search engines will crawl, users don't need to wait for anything to see the initial render, and the page basically works for users who have disabled javascript.

Rosenfeld answered 26/3, 2016 at 11:36 Comment(1)
Thanks for your answer. Do you know good article to use React with Varnish?Tercentenary
F
0

In additions to above answers, in CSR side you also have to replace ReactDOM.render to ReactDOM.hydrate

Also you can use same LikeButton file in SSR and CSR, only thing happen is SSR side onClick event will not response to any thing

Fredrick answered 6/7, 2022 at 18:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.