1

我在渲染同构应用程序时遇到问题,当我不使用 react-router(1.0.0-rc3) 时它可以正常工作,但是当我引入路由器时,特别是一个呈现如下链接的组件:

const React = require('react');
const Link = require('react-router').Link;
module.exports = class About extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <ul>
        <li><Link to="/about">About</Link></li>
        <li><Link to="/list">List</Link></li>
      </ul>
    );
  }
}

服务器和客户端的输出不同,我收到此警告

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) n><a class="" href="#/about" data-reacti
(server) n><a class="" href="/about" data-reactid

所以服务器(或客户端)以不同的方式呈现 href 标签,这就是我呈现服务器端的方式

const React = require('react');
const reactDOMServer = require('react-dom/server');
const tmpl = require('blueimp-tmpl');
const fs = require('fs');
const path = require('path');
const templateFunction = tmpl.tmpl;
const match = require('react-router').match;
const RoutingContext = require('react-router').RoutingContext;

const routes = require('../../app/routes');
const App = require('../../app/app');
const serverProps = require('../../server.props');

templateFunction.load = function(id) {
  const filePath = path.resolve(serverProps.publicPath, id);
  return fs.readFileSync(filePath, "utf8");
};

module.exports = function*(next) {
  match({ routes, location: this.url }, (error, redirectLocation, renderProps) => {
      if (error) {
        this.throw(error.message);
      } else if (redirectLocation) {
        this.redirect(redirectLocation.pathname + redirectLocation.search);
      } else if (renderProps) {
        const html = reactDOMServer.renderToString( <RoutingContext {...renderProps} /> );        
        this.body = templateFunction("index.html", html);
      } else {
        this.throw(404);
      }
    });
};

我在这里使用的模板引擎是 blueimp-tmpl,我首先怀疑它可能在渲染时对 href-hash-sign 做一些事情,但是我记录了输出 renderToString 并且在进入模板之前 href-hash-sign 已经消失了.

我在 npm 历史包(它是 react-router 的对等依赖项)中进行了一些挖掘,它似乎是生成链接的 href 部分的组件,但无法弄清楚为什么它以不同的方式呈现它。

有任何想法吗?

编辑,这是路线

const React = require('react');
const Router = require('react-router').Router;
const Route = require('react-router').Route;

const BaseLayout = require("./components/base-layout/base-layout");
const List = require("./components/list/list");
const About = require("./components/about/about");

module.exports = (
  <Router>
      <Route path="/" component={BaseLayout}>
        <Route path="about" component={About} />
        <Route path="list" component={List} />
      </Route>
    </Router>
);

BR TWD

4

1 回答 1

1

好的,解决了。

最初的问题,客户端的 href 获得哈希标记类型链接是因为缺少历史配置解决了:

// router.js
const React = require('react');
const Router = require('react-router').Router;
const Route = require('react-router').Route;

const BaseLayout = require("./components/base-layout/base-layout");
const List = require("./components/list/list");
const About = require("./components/about/about");

// This was the missing part... 
const createBrowserHistory = require('history/lib/createBrowserHistory');

module.exports = (
  <Router history={createBrowserHistory()}>
      <Route path="/" component={BaseLayout}>
        <Route path="about" component={About} />
        <Route path="list" component={List} />
      </Route>
    </Router>
);

链接现在看起来不错,但这导致服务器端渲染失败,因为我在渲染时使用了整个路由器,而 createBrowserHistory 需要 DOM 才能工作。通过将路由拉出到另一个文件来解决,如下所示:

// routes.js
const React = require('react');
const Route = require('react-router').Route;

const BaseLayout = require("./components/base-layout/base-layout");
const List = require("./components/list/list");
const About = require("./components/about/about");

module.exports = (
  <Route path="/" component={BaseLayout}>
    <Route path="about" component={About}/>
    <Route path="list" component={List}/>
  </Route>
);

并使用服务器上的纯路由,如服务器渲染文档所示。这使服务器端渲染工作,但现在我再次破坏了客户端渲染,因为我的路由器组件不了解如何使用在不同文件中声明的路由,使用正确的语法很容易修复它:

// router.js
const React = require('react');
const Router = require('react-router').Router;

const routes = require("./routes");
const createBrowserHistory = require('history/lib/createBrowserHistory');
module.exports = (
  <Router routes={routes} history={createBrowserHistory()}>    
  </Router>
);
于 2015-11-08T13:26:13.887 回答