2015-11-03 75 views
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歷史包(它是一個反應路由器的對等體依賴)中做了一些挖掘,它似乎是生成鏈接的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

+1

你能告訴我們你的路由/路由器是如何建立的嗎?我懷疑這可能與您使用react-router的歷史api有關 – deowk

回答

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.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> 
); 
相關問題