StaticRouter 为 <Link> 标签呈现一个前导斜杠 [react-router 4.0.0]

StaticRouter renders a leading slash for <Link> tags [react-router 4.0.0]

我正在尝试使用 react-router 4.0.0 设置一个通用的 React 应用程序。

除了我的 Link 标记在服务器端和客户端上呈现不同这一事实外,服务器端呈现工作正常。这是错误消息:

Warning: React attempted to reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is different on the client or server:

(client) o Furb</h1><a href="./" data-reactid="4"
(server) o Furb</h1><a href="/./" data-reactid="4

我对 react-router 和一般的反应还很陌生,所以请记住这可能是我代码中的一个小错误。另外,我边学边学,所以,我的代码中可能还有其他吵闹的错误,提前道歉。

在网上查找,我想出了一个涵盖类似问题的错误修复程序:https://github.com/ReactTraining/react-router/pull/4484

不过react-router 4.0.0已经包含了这个补丁(我戳了一下代码,确实修复了)。因此,我的问题不是由这个引起的。

经过大量修改后,我怀疑我的配置或错误是由于我对我正在做的事情的理解有限所致。例如,对于 StaticRouter,我使用 location={req.originalUrl} 而不是 location={req.url},因为 req.url 似乎总是 /,我不确定为什么。

我在下面发布了我认为相关的文件,但如果你想查看完整代码,你可以在这里找到它:https://github.com/magp/furb/tree/universal

package.json

{
  "name": "furb",
  "version": "0.0.1",
  "description": "A boilerplate for Firebase-UniversalRedux-Bootstrap/MaterialUI projects",
  "main": "app/server.jsx",
  "scripts": {
    "start": "concurrently --kill-others \"npm run start:api\" \"npm run start:back\"",
    "start:back": "node app/serverlauncher.js",
    "start:api": "node api/server.js",
    "clean": "rimraf static",
    "serve:prod": "http-server ./static -o -p 3032",
    "build:app": "NODE_ENV=production webpack --config config/webpack-prod-config.js",
    "build": "npm run clean && npm run build:app && npm run serve:prod",
    "test": "echo 'NODE_ENV=production mocha './tests/**/*.spec.js' --compilers js:babel-core/register'",
    "lint": "eslint --config=./.eslintrc app/**/**/*.jsx"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/magp/furb.git"
  },
  "keywords": [
    "Boilerplate",
    "React",
    "Redux",
    "UniversalJS",
    "Bootstrap",
    "MaterialUI"
  ],
  "author": "magp",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/magp/furb/issues"
  },
  "homepage": "https://github.com/magp/furb#readme",
  "dependencies": {
    "express": "^4.15.2",
    "history": "^4.6.1",
    "react": "^15.4.2",
    "react-dom": "^15.4.2",
    "react-hot-loader": "^3.0.0-beta.6",
    "react-router-dom": "^4.0.0"
  },
  "devDependencies": {
    "babel-core": "^6.24.0",
    "babel-loader": "^6.4.0",
    "babel-preset-es2015": "^6.24.0",
    "babel-preset-react": "^6.23.0",
    "concurrently": "^3.4.0",
    "eslint": "^3.17.1",
    "eslint-config-airbnb": "^14.1.0",
    "eslint-plugin-import": "^2.2.0",
    "eslint-plugin-jsx-a11y": "^4.0.0",
    "eslint-plugin-react": "^6.10.0",
    "html-webpack-plugin": "^2.28.0",
    "http-server": "^0.9.0",
    "node-sass": "^4.5.0",
    "rimraf": "^2.6.1",
    "sass-loader": "^6.0.3",
    "style-loader": "^0.14.0",
    "webpack": "^2.2.1",
    "webpack-dev-middleware": "^1.10.1",
    "webpack-hot-middleware": "^2.17.1"
  }
}

app/serverlauncher.js

require('babel-register')({
  presets: [ 'es2015', 'react' ]
});

var app = require('./server.jsx');

app/server.jsx

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

var React = require('react');
var ReactDOMServer = require('react-dom/server');
var StaticRouter = require('react-router-dom/StaticRouter').default;
var webpack = require('webpack');

var config = require('../config/webpack-dev-config');
var Routes = require('./routes/Routes.jsx').default;

var app = express();
var compiler = webpack(config);

app.use(require('webpack-dev-middleware')(compiler, {
  noInfo: true,
  publicPath: config.output.publicPath
}));

app.use(require('webpack-hot-middleware')(compiler));

const routes = [
    '/',
    '/about'
];

app.use('*', function (req, res, next) {
  const context = {};
  const componentHTML = ReactDOMServer.renderToString(<StaticRouter context={context} location={req.originalUrl}><Routes /></StaticRouter>);

  const HTML = `
    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <title>Static</title>
      </head>
      <body>
        <div id="app">${componentHTML}</div>
        <script type="text/javascript" src="/static/source.js"></script>
      </body>
    </html>
  `;
  res.end(HTML);
});

const PORT = process.env.PORT || 3030;

app.listen(PORT, 'localhost', function(err) {
  if (err) {
    console.log(err);
    return;
  }
  console.log('Listening at http://localhost:3030');
});

app/routes/Routes.jsx

import React from 'react';
import { Route, Switch } from 'react-router-dom';

import List from '../components/List';
import About from '../components/About';
import NotFound from '../components/NotFound';

import links from '../../api/data/links.json';

const linksarr = Object.keys(links).map(function(k) { return links[k] });

function Routes() {
  return (
    <Switch>
      <Route exact path="/" render={props => (<List links={linksarr} {...props} />)} />
      <Route exact path="/about" component={About} />
      <Route component={NotFound} />
    </Switch>
  );
}

export default Routes;

app/components/Layout.jsx

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

function Layout() {
  return (
    <div>
      <h1>Welcome to Furb</h1>
      <Link to="./">Home</Link>
      <Link to="./about">About</Link>
      <Link to="./test">Test</Link>
    </div>
  );
}

export default Layout;

请原谅这么长的问题,并提前感谢您提供的任何帮助。

尝试删除链接的 "to" 字段中的句点。它应该只是“/”、“/about”等,而不是“./about”。路由不是文件路径,它们是由路由器解析和解释的,句号会混淆它。

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

function Layout() {
  return (
    <div>
      <h1>Welcome to Furb</h1>
      <Link to="/">Home</Link>
      <Link to="/about">About</Link>
      <Link to="/test">Test</Link>
    </div>
  );
}

export default Layout;