具有服务器端呈现的React-router 4:TypeError:无法读取null的属性“pathname”

时间:2017-01-29 10:15:27

标签: reactjs express webpack-2 serverside-rendering react-router-v4

我正在使用webpack @ 2和React-Router @ 4构建一个React应用程序。在开发模式下,一切正常,但对于生产,我想使用服务器端渲染,它会导致错误:

TypeError: Cannot read property 'pathname' of null
    at isActive (/react-app/node_modules/react-router/Link.js:120:46)
    at Object.children (/react-app/node_modules/react-router/Link.js:80:24)
    at Subscriber.render (/react-app/node_modules/react-broadcast/Subscriber.js:65:23)
    at /react-app/build/app.js:18:2455
    at s (/react-app/build/app.js:17:22003)
    at x._renderValidatedComponentWithoutOwnerOrContext (/react-app/build/app.js:18:2433)
    at x._renderValidatedComponent (/react-app/build/app.js:18:2741)
    at x.performInitialMount (/react-app/build/app.js:17:28173)
    at x.mountComponent (/react-app/build/app.js:17:26586)
    at Object.s.mountComponent (/react-app/build/app.js:1:27885)

这是我的App组件:

import React from 'react';
import { render } from 'react-dom';
import { Match, Miss, Link } from 'react-router';

import Home from './Home';
import About from './About';
import NoMatch from './NoMatch';

export default () => (
  <div>
    <ul>
      <li><Link to="/">Home</Link></li>
      <li><Link to="/about">About</Link></li>
    </ul>

    <hr/>

    <Match exactly pattern="/" component={Home} />
    <Match pattern="/about" component={About} />

    <Miss component={NoMatch}/>
  </div>
);

这是webpack的入口点:

import React from 'react';
import express from 'express';
import morgan from 'morgan';
import path from 'path';
import { ServerRouter, createServerRenderContext } from 'react-router';
import { renderToString } from 'react-dom/server';

import App from './components/App';

const app = express();

app.use(morgan('combined'));
app.use(express.static(path.join(__dirname)));

app.set('view engine', 'pug');
app.set('views', path.join(__dirname, '../src/views'));

app.get('*', function(req, res) {
  const context = createServerRenderContext();

  let markup = renderToString(
    <ServerRouter
      location={req.url}
      context={context}
    >   
      <App/>
    </ServerRouter>
  );  

  const result = context.getResult();

  if (result.redirect) {
    res.writeHead(301, {
      Location: result.redirect.pathname
    }); 

    res.end();
  } else {
    if (result.missed) {
      res.writeHead(404);

      markup = renderToString(
        <ServerRouter
          location={req.url}
          context={context}
        >   
          <App/>
        </ServerRouter>
      );  

  const result = context.getResult();

  if (result.redirect) {
    res.writeHead(301, {
      Location: result.redirect.pathname
    }); 

    res.end();
  } else {
    if (result.missed) {
      res.writeHead(404);

      markup = renderToString(
        <ServerRouter
          location={req.url}
          context={context}
        >   
          <App/>
        </ServerRouter>
      );  
    }

    res.render('index', { includeCss: true, reactMarkup: renderToString(<App />) });
    res.end();
  }
});

app.listen(3000);

最后是webpack的配置:

const fs = require('fs');
const path = require('path');
const webpack = require('webpack');

const config = {
  target: 'node',

  entry: [
    path.join(__dirname, 'src/js/server.prod.js')
  ],

  output: {
    path: path.join(__dirname, 'build'),
    filename: 'app.js'
  },

  resolve: {
    extensions: ['.js', '.jsx']
  },

  module: {
    rules: [
      {
        test: /\.jsx?$/,
        loader: 'babel-loader',
        exclude: /node_modules/
      },

      {
        test: /\.(eot|png|svg|ttf|woff|woff2)$/,
        use: 'file-loader'
      }
    ]
  },

  externals: fs.readdirSync('node_modules').reduce(function(acc, mod) {
    if (mod === '.bin') {
      return acc;
    }

    acc[mod] = 'commonjs ' + mod;
    return acc;
  }, {}),

  node:  {
    console: false,
    global: false,
    process: false,
    Buffer: false,
    __filename: false,
    __dirname: false,
  },

  plugins: [
    new webpack.optimize.UglifyJsPlugin()
  ],

  bail: true
};

module.exports = config;

有什么想法吗?

2 个答案:

答案 0 :(得分:0)

在Home.js和About.js

<script>
    // Immediately Invoked Function Expression instead of function declaration
    (function() {

        var head  = document.querySelector('head');
        var link  = document.createElement('link');
        link.rel  = 'stylesheet';

        var theTime = new Date().getHours();
        console.log (theTime);

        if (theTime >= 9 && theTime < 17) {
            link.href='/nuvoladigital.com.br/css/stylesDAY.css';
        } else {
            link.href='/nuvoladigital.com.br/css/stylesNIGHT.css';
        }

        head.appendChild(link);
    }());

</script>

<noscript>
  <link href="/nuvoladigital.com.br/css/stylesnight.css" rel="stylesheet">   
</noscript>

答案 1 :(得分:0)

您要导入的链接组件来自&#39; react-router&#39;这是问题,这将适用于react-router版本&lt; 4.0。从react-router版本4开始,此Link包是react-router-dom的一部分。所以你需要先安装react-router-dom:

npm install --save react-router-dom

并像这样导入:

import { Link } from 'react-router-dom'