Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

rendering react on server

I've been trying to figure out how to render react on the server (node/express) and finally found a simple enough tutorial to understand what's going on. But now, after setting everything up, I'm getting an error in the React.render method:

here's my component file:

var React = require('react');
var box = React.createClass({
    render: function() {
        return (
            <div style='padding: 10px'>
                this.props.text
            </div>
        );
    }
});

React.render(<box text='testing server side'/>, document.body);
module.exports = box;

I get an error when I run npm start:

document is not defined

how do I get around this? do I need or not need the render method?

to give more context, this box component is being required by another component:

var React = require('react');
var Box = require('../react-jsx/box.js'); //this is the box component
var Component = React.createClass({
    render: function() {
        return (
            <html>
                <head>
                    <title>
                        React Server Rendering
                    </title>
                </head>
                <body>
                    <Box text='testing'/>
                    <script src="public/bundle.js"></script>
                </body>
            </html>
        );
    }
});

module.exports = Component;

and this is all being used in index.js

require('node-jsx').install();
var React = require('react');
var Component = require('../custom-modules/test-react-server-module.js');
var express = require('express');
var router = express.Router();

router.get('/react', function(req, res, next) {
  var markup = React.renderToString(Component());
  res.send(markup);
});

module.exports = router;

and if I remove the render method I get this error in the browser:

Cannot read property '__reactAutoBindMap' of undefined

I saw some people saying that may be due to the jsx transformer being old, but I think I have the latest version

I'm out of ideas

like image 234
duxfox-- Avatar asked Dec 22 '15 03:12

duxfox--


People also ask

Can React be rendered on server-side?

Yes! This is where server-side rendering for React comes in. In this article, I want to introduce you to server-side rending (SSR) with React, reasons to use it, and some popular frameworks for rendering React on the server side.

Is React client or server-side rendering?

The client-side framework manages to update UI with changed data by re-rendering only that particular DOM element. Today, Angular and React. js are some of the best examples of libraries used in client-side rendering.

How do I run the React App on my server?

For your React app, you'll have to drag and drop the build folder onto the Netlify Dashboard. Run npm run build beforehand to deploy the latest build. You can also connect GitHub, GitLab, or Bitbucket, depending on where your project is stored. This allows automatic deployment whenever you push your changes.

Is server-side rendering worth it?

Some server-side rendering advantages include: A server-side rendered application enables pages to load faster, improving the user experience. When rendering server-side, search engines can easily index and crawl content because the content can be rendered before the page is loaded, which is ideal for SEO.


2 Answers

First of all, I'd recommend update your React version. The current version exposes two different Top-Level API's: React, which is generally used to create components and ReactDOM, which exposes DOM-specific methods to be used at the top level of your app.

There is to things to point out here:

  • You are trying to run an code that is supposed to be executed only at the browser. There is no document in NodeJS. I'd suggest using webpack to pack this component files and serve them on browser.

  • For an isomorphic React application, you need to have a client.js file that calls the render function for the same component you are trying to render inside index.js. Got it?

Understand the ReactDOM.render, as the documentation states:

Render a ReactElement into the DOM in the supplied container and return a reference to the component (or returns null for stateless components).

If the ReactElement was previously rendered into container, this will perform an update on it and only mutate the DOM as necessary to reflect the latest React component.

Keep in mind, again, that ReactDOM.render should be only used a few times and generally at the top level of your app, just one time.

Having said this, your box.js should look like:

var React = require('react');
var box = React.createClass({
    render: function() {
        return (
            <div style='padding: 10px'>
                this.props.text
            </div>
        );
    }
});

module.exports = box;

For this to properly work, you will need to create a main component main-component-file.js:

var React = require('react');
var Box = require('../react-jsx/box.js'); //this is the box component
var Component = React.createClass({
    render: function() {
        return (
            <html>
                <head>
                    <title>
                        React Server Rendering
                    </title>
                </head>
                <body>
                    <Box text='testing'/>
                    <script src="public/bundle.js"></script>
                </body>
            </html>
        );
    }
});

module.exports = Component;

Inside your bundle.js you need to make sure that this is being called so the main component tries to re-render:

var React = require('react');
var ReactDOM = require('react-dom');
var Component = require('main-component-file.js'); 

ReactDOM.render(<Component/>, document.body);

At last but not least: index.js, the server file. Change React.renderToString to ReactDOMServer.renderToString, create a React Element from your main component and use it:

var element = React.createElement(Component)
router.get('/react', function(req, res, next) {
  var markup = ReactDOMServer.renderToString(element);
  res.send(markup);
});

Don't forget to include the npm package react-dom/server at your index.js.

References used in the article:

  • React.createElement

  • ReactDOM.render() docs

  • ReactDOMServer docs

like image 187
Inacio Schweller Avatar answered Sep 24 '22 07:09

Inacio Schweller


You should delete this

React.render(<box text='testing server side'/>, document.body);

There is no need for it. What you are essentially telling React to do is render it right then and there.

document.body doesn't exist yet because you are rendering it server-side and you also don't need it because you render the component in the renderToString function upon request in the router. (Also I think @PeterLyons is correct so take a look at his answer too).

Also if you are strictly using React for views only, you might want to take a look at express-react-views. They have a good tutorial of how to use React with Express and you essentially can use it for server-side rendering only. I don't think it's as ideal as using react-router depending on what you're building but it illustrates how React is handling the server-side rendering and works with Express.

like image 39
aug Avatar answered Sep 23 '22 07:09

aug