rendering react on server

- 1 answer

Ad

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

Ad

Answer

Ad

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:

Ad
source: stackoverflow.com
Ad