React、redux 和 react-router 服务器端渲染

React, redux, and react-router server side rendering

尝试在服务器上呈现我的 React 应用程序时,我收到以下错误:

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.

这是我的 server.js 代码,为简洁起见,我删除了服务器配置。

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')
        }
     });

正在调用 if 语句的 renderProps 块,这是抛出错误的地方。

编辑:当我从 react-router 导入后 console.log RouterContext 时,我变得不确定。

您可以在此处查看我的 package.json 版本:http://pastebin.com/mpb6XSKu

问题是我指的是 master 的最新 react-router 文档,其中提到了 "RouterContext." 在版本 1.0.2 中,它被命名为 "RoutingContext." 更改我的代码以引用后者解决了其中一个问题。这是我最终的工作同构服务器,除了呈现静态资产之外:

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');
  });
});