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>
);

そして、ここに示されているように、サーバーで純粋なルートを使用しますServer Rendering Docs。これにより、サーバー側のレンダリングが機能しましたが、Router コンポーネントが別のファイルで宣言されたルートの使用方法を理解していなかったため、クライアント側のレンダリングが再び中断されました。正しい構文を使用することで簡単に修正されました。

// 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 に答える