reactjsreact-routerreact-ssr

Reactjs TypeError: Cannot read property 'toLowerCase' of undefined (react-router-config)


I'm using Reactjs for server-side rendering, using the react-router-config package for achieving ssr but after change React Router to react-router-config code. Application stopped working

The Error is displayed to me after I change code normal React router to react-router-config code

in StaticRouter

<StaticRouter location={req.path} context={{}}>
  <div>{renderRoutes(Routes)}</div>
</StaticRouter> 

My package.json file

{
  "name": "react-ssr",
  "version": "1.0.0",
  "description": "Server side rendering project",
  "main": "index.js",
  "scripts": {
    "dev": "npm-run-all --parallel dev:*",
    "dev:server": "nodemon --watch build --exec \"node build/bundle.js\"",
    "dev:build-server": "webpack --config webpack.server.js --watch",
    "dev:build-client": "webpack --config webpack.client.js --watch"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "axios": "0.16.2",
    "babel-cli": "6.26.0",
    "babel-core": "6.26.0",
    "babel-loader": "7.1.2",
    "babel-preset-env": "1.6.0",
    "babel-preset-es2015": "6.24.1",
    "babel-preset-es2017": "6.24.1",
    "babel-preset-react": "6.24.1",
    "babel-preset-stage-0": "6.24.1",
    "compression": "1.7.0",
    "concurrently": "3.5.0",
    "express": "4.15.4",
    "express-http-proxy": "1.0.6",
    "lodash": "4.17.4",
    "nodemon": "1.12.0",
    "npm-run-all": "4.1.1",
    "react": "16.0.0",
    "react-dom": "16.0.0",
    "react-helmet": "5.2.0",
    "react-redux": "5.0.6",
    "react-router-config": "1.0.0-beta.4",
    "react-router-dom": "4.2.2",
    "redux": "3.7.2",
    "redux-thunk": "2.2.0",
    "serialize-javascript": "1.4.0",
    "webpack": "3.5.6",
    "webpack-dev-server": "2.8.2",
    "webpack-merge": "4.1.0",
    "webpack-node-externals": "1.6.0"
  }
}

Routes.js file

    import React from 'react';
    import Home from './components/Home';
    import UsersList from './components/UsersList';

    export default [
        {
            path: '/',
            components: Home,
            exact: true
        },
        {
            path: '/users',
            components: UsersList
        }
    ];

clinet.js file

    // Startup point the client side application
    import 'babel-polyfill';
    import React from 'react';
    import ReactDOM from 'react-dom';
    import { BrowserRouter } from 'react-router-dom';
    import { createStore, applyMiddleware } from 'redux';
    import thunk from 'redux-thunk';
    import { Provider } from 'react-redux';
    import { renderRoutes } from 'react-router-config';
    import Routes from './Routes';
    import reducers from './reducers';

    const store = createStore(reducers, {}, applyMiddleware(thunk))

    ReactDOM.hydrate(
        <Provider store={store}>
            <BrowserRouter>
            <div>{renderRoutes(Routes)}</div>
            </BrowserRouter>
        </Provider>,
         document.querySelector('#root'));

renderer.js

    import React from 'react';
    import { renderToString } from 'react-dom/server';
    import { StaticRouter } from 'react-router-dom';
    import { Provider } from 'react-redux';
    import { renderRoutes } from 'react-router-config';
    import Routes from '../client/Routes';

    export default (req, store) => {
        const content = renderToString(
            <Provider store={store}>
                <StaticRouter location={req.path} context={{}}>
                   <div>{renderRoutes(Routes)}</div>
                </StaticRouter>    
            </Provider>
        );

        return `
        <html>
            <head></head>
            <body>
                <div id="root">${content}</div>
                <script src="bundle.js"></script>
            </body>
        </html>
        `;
    };

index.js file

    import 'babel-polyfill';
    import express from 'express';
    import renderer from './helpers/renderer';
    import createStore from './helpers/createStore';
    const app = express();

    app.use(express.static('public'));
    app.get('*', (req,res) => {
        const store = createStore();
        //some logic to initialize
        // and load data into the store
        res.send(renderer(req, store));  
    });

    app.listen(3000, () =>{
        console.log('Listening on port 3000');
    });

Error Output

    TypeError: Cannot read property 'toLowerCase' of undefined
        at ReactDOMServerRenderer.renderDOM (/var/www/html/server/node_modules/react-dom/cjs/react-dom-server.node.development.js:2776:28)
        at ReactDOMServerRenderer.render (/var/www/html/server/node_modules/react-dom/cjs/react-dom-server.node.development.js:2755:23)
        at ReactDOMServerRenderer.read (/var/www/html/server/node_modules/react-dom/cjs/react-dom-server.node.development.js:2722:19)
        at renderToString (/var/www/html/server/node_modules/react-dom/cjs/react-dom-server.node.development.js:2980:25)
        at exports.default (/var/www/html/server/build/bundle.js:218:46)
        at /var/www/html/server/build/bundle.js:169:37
        at Layer.handle [as handle_request] (/var/www/html/server/node_modules/express/lib/router/layer.js:95:5)
        at next (/var/www/html/server/node_modules/express/lib/router/route.js:137:13)
        at Route.dispatch (/var/www/html/server/node_modules/express/lib/router/route.js:112:3)
        at Layer.handle [as handle_request] (/var/www/html/server/node_modules/express/lib/router/layer.js:95:5)

Solution

  • As per documentation of react-router-config, key has to be component not components.

    In your code it is in Routes.js file. Can you try by changing it to component