asiniy asiniy - 4 months ago 34
React JSX Question

React.js how to avoid server rendering of some components?

I want to render React on the server only for SEO purposes, and some components aren't needed to render on the server. How can I ignore server rendering of some components in this case?

Answer

I'd recommend a Higher-order Component that uses a parameter within React's context to control rendering. This will allow you to wrap components that should only render on the client with the HoC which can decide to either render the wrapped component or nothing if on the server.

var React = require('react');
var ReactDOMServer = require('react-dom/server');

// Should be added as a static contextTypes property on any component
// needing access to the parameter. In this case, it's only the HoC
var serverContextTypes = {
    isServer: React.PropTypes.bool
};

// Should be the root component of your server-side render to inject
// the parameter into context
var ServerContext = React.createClass({
    getChildContext: function () {
        return {
            isServer: true
        };
    },

    render: function () {
        // Only allows a single child
        return React.Children.only(this.props.children);
    }
});

// Tells React which context types to pass to ServerContext's children
ServerContext.childContextTypes = serverContextTypes;

ServerContext.propTypes = {
    children: React.PropTypes.element.isRequired
};

// The HoC that determines if the wrapped component should be rendered
var ClientOnly = function (Wrapped) {
    var Component = React.createClass({
        render: function () {
            if (this.context.isServer) {
                return null;
            } else {
                return React.createElement(Wrapped, this.props);
            }
        }
    });

    Component.contextTypes = serverContextTypes;

    return Component;
};

// Example React.Component that will always render
var Content = React.createClass({
    render: function () {
        return React.createElement('main', null, 'Important content that should always render');
    }
});

// Example React.Component that will be omitted from server-side rendering
var Extra = ClientOnly(React.createClass({
    render: function () {
        return React.createElement('aside', null, 'Content to exclude in a React.Component');
    }
}));

// Example SFC that will be omitted from server-side rendering
var ExtraSFC = ClientOnly(function () {
    return React.createElement('aside', null, 'Content to exclude in a Stateless Functional Component');
});

// The App!
var App = React.createClass({
    render: function () {
        return React.createElement('div', {className: 'app'}, [
            React.createElement(Extra),
            React.createElement(Content),
            React.createElement(ExtraSFC)
        ]);
    }
});

var element = React.createElement(ServerContext, null, 
    React.createElement(App)
);

console.log(ReactDOMServer.renderToString(element));