1

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

除了我的链接标签在服务器和客户端上的呈现方式不同之外,服务器端呈现工作正常。这是错误消息:

警告:React 尝试在容器中重用标记,但校验和无效。这通常意味着您正在使用服务器渲染,并且在服务器上生成的标记不是客户端所期望的。React 注入了新的标记来补偿哪些工作,但是您已经失去了服务器渲染的许多好处。相反,找出为什么生成的标记在客户端或服务器上是不同的:

(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

包.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"
  }
}

应用程序/serverlauncher.js

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

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

应用程序/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');
});

应用程序/路由/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;

应用程序/组件/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;

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

4

1 回答 1

1

尝试在链接的“到”字段中删除句点。它应该只是“/”、“/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;
于 2017-03-17T17:12:45.637 回答