Context As Undefined When Using React Router 4 For Server Side Rendering

I'm working on implementing server-side rendering with React Router 4 at a basic level to understand how it works. However, I am facing several problems and it is not clear in the React Router documentation how to solve them:

1) My context variable at / server / routes is undefined.

I've seen in previous tutorials that React Router used createServerRenderContext (); however, their documentation is not mentioned anymore, so I assume they got rid of it. I thought the StaticRouter should create your context for you when it renders? How can I define my context?

2) My html variable which renders the StaticRouter as a string shows these two errors in the console:

Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it defined in.

Uncaught Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it defined in.

      

I don't quite understand why this is a problem. I believe this is exported correctly and I am passing this through renderToString. Why is this giving me an error?

Any help is greatly appreciated! Here's my code below:

Server side

/server/server.js

import express from 'express'
import router from './routes/index.js'

const app = express();

app.use(express.static('public'));
app.use(router)

const PORT = 3000;
app.listen(PORT, function(){
  console.log('Listening on ' + PORT)
});

      

/server/routes/index.js

import { Router } from 'express'
import React from 'react'
import ReactDOMServer from 'react-dom/server'
import { StaticRouter } from 'react-router'
import App from '../../client/App'

const router = Router();

router.get('*', function(request, response) {

  const context = {}

  const html = ReactDOMServer.renderToString(
    <StaticRouter location={request.url} context={context}>
      <App/>
    </StaticRouter>
  );

  if (context.url) {
    response.writeHead(301, {
      Location: context.url
    })
    response.end()
  } else {
    response.write(html)
    response.end()
  }
});

export default router

      

Client side

/client/index.js

import React from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter } from 'react-router';

import App from './App'

const props = window.PROPS;

ReactDOM.render(
  <BrowserRouter>
    <App {...props} />
  </BrowserRouter>,
  document
);

      

/client/App.js

import React from 'react'

class App extends React.Component {
  constructor() {
      super()
  }
  handleClick() {
    alert()
  }
  render() {
    return (
      <html>
        <head>
          <title>{this.props.title}</title>
          <link rel="stylesheet" href="/style.css" />
        </head>
        <body>
          <main>
            <h1>{this.props.title}</h1>
            <p>This is some text that makes up a paragraph</p>
            <button onClick={this.handleClick}>Click me</button>
          </main>
          <script dangerouslySetInnerHTML={{
            __html: 'window.PROPS=' + JSON.stringify(this.props)
          }} />
          <script src="/bundle.js" />
        </body>
      </html>
    )
  }
}

export default App;

      

Webpack.config.js

var webpack = require('webpack');
var path = require('path');

module.exports = {
  entry: './src/client/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'public'),
    publicPath: '/public/'
  },
  module: {
    rules: [
      {
        test: /\.js?$/,
        exclude: /node_modules/,
        include: path.join(__dirname, 'src'),
        use: [
          {
            loader: 'babel-loader',
            query: {
              presets: ['react', ['es2015', { 'modules': false }], 'stage-0'],
              plugins: ['react-html-attrs', 'transform-class-properties', 'transform-decorators-legacy']
            }
          }
        ]
      }
    ]
  }
};

      

+3


source to share





All Articles