Ad

React, Redux, And React-router Server Side Rendering

- 1 answer

When trying to render my react application on the server, I'm receiving the following error:

Error: Uncaught error: Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined.

Here is my server.js code, I've removed the server configuration for brevity.

import hapi from 'hapi';
import inert from 'inert';
import path from 'path';
import fs from 'fs';
import React from 'react';
import { ReactDOM, renderToString } from 'react-dom/server';
import { RouterContext, ReactRouter, match } from 'react-router';
import { Provider } from 'react-redux';
import routes from './src/config/routes';
import store from './src/flux/store';

...
      match({routes, location: request.url.path}, function(err, redirectLocation, renderProps) {

        if (err) {
          reply(err.message).status(500);
        } else if (redirectLocation) {
          reply()
            .redirect(redirectLocation.pathname + redirectLocation.search)
            .code(302);

        } else if (renderProps) {

          var element = (
            <RouterContext {...renderProps} />
          );

          console.log(element);

          reply(renderToString(element)).code(200);

        } else {
          reply('Page Not Found')
        }
     });

The renderProps block of the if statement is getting called, and this is where the error is thrown.

EDIT: When I console.log RouterContext after my import from react-router, I'm getting undefined.

You can view my package.json for versions here: http://pastebin.com/mpb6XSKu

Ad

Answer

The issue is that I was referring to the latest react-router docs for master which referred to "RouterContext." In version 1.0.2, this was named "RoutingContext." Changing my code to refer to the latter fixed one of the issues. This is my final working isomorphic server short of rendering static assets:

import hapi from 'hapi';
import inert from 'inert';
import React from 'react';
import { createStore } from 'redux';
import { ReactDOM, renderToString } from 'react-dom/server';
import { RoutingContext, ReactRouter, match } from 'react-router';
import { Provider } from 'react-redux';
import routes from './src/config/routes';
import initializeStore from './src/flux/store';

const server = new hapi.Server();

server.register(inert, err => {

  if (err) {
    throw err;
  }

  server.connection({
    host: '0.0.0.0',
    port: 80
  });

  server.route({
    method: 'GET',
    path: '/{path*}',
    handler: function (request, reply) {

      var url = request.url.path;

      var matcher = {
        routes,
        location: request.url.path
      };

      match(matcher, function(err, redirectLocation, renderProps) {

        if (err) {

          reply(err.message).status(500);

        } else if (redirectLocation) {

          reply()
            .redirect(redirectLocation.pathname + redirectLocation.search)
            .code(302);

        } else if (renderProps) {

          var element = (
            <Provider store={initializeStore()}>
              <RoutingContext {...renderProps} /> 
            </Provider>
          );

          reply(renderToString(element)).code(200);

        } else {
          reply('Page Not Found');
        }
     });
   }
  });

  server.start(function (err) {
    if (err) {
      throw err;
    }

    console.log('Server started');
  });
});
Ad
source: stackoverflow.com
Ad