React服务端渲染中react-router及Link组件异常问题求助
首先得明确:React Router 4把核心功能和平台特定实现拆分开了——react-router是核心基础库,而浏览器端的Link、BrowserRouter,以及服务器端用的StaticRouter都在react-router-dom包里。你之前直接从react-router导入Link和默认导出的做法,在v4版本里完全不适用,这就是为什么R会返回undefined的原因。
下面一步步帮你修复问题:
1. 修正组件导入语句
把原来的导入代码替换成下面的写法,区分服务器端和客户端的路由组件:
// 服务器端代码 import React from 'react'; import { Link, StaticRouter } from 'react-router-dom'; // 客户端代码(替换StaticRouter为BrowserRouter) import React from 'react'; import { Link, BrowserRouter } from 'react-router-dom';
Link组件只存在于面向浏览器的react-router-dom和面向原生应用的react-router-native中,react-router核心库并不提供这个组件。
2. 配置服务器端渲染逻辑
在服务器端(比如Express路由里),你需要用StaticRouter包裹整个应用,传入当前请求的location和一个context对象(用来处理重定向等路由逻辑):
// 服务器端示例代码(Express框架) import React from 'react'; import { renderToString } from 'react-dom/server'; import { StaticRouter } from 'react-router-dom'; import App from './App'; app.get('*', (req, res) => { const context = {}; // 用StaticRouter包裹应用,渲染成字符串 const appHtml = renderToString( <StaticRouter location={req.url} context={context}> <App /> </StaticRouter> ); // 处理路由重定向 if (context.url) { res.redirect(301, context.url); } else { res.send(` <!DOCTYPE html> <html> <head> <title>SSR React App</title> </head> <body> <div id="root">${appHtml}</div> <!-- 客户端打包脚本 --> <script src="/client-bundle.js"></script> </body> </html> `); } });
3. 配置客户端渲染逻辑
客户端需要用BrowserRouter包裹应用,这样点击Link时会使用HTML5的pushState API,完全在客户端处理路由跳转,不会触发服务器请求:
// 客户端入口文件 import React from 'react'; import { hydrate } from 'react-dom'; import { BrowserRouter } from 'react-router-dom'; import App from './App'; hydrate( <BrowserRouter> <App /> </BrowserRouter>, document.getElementById('root') );
4. 共享路由配置(推荐做法)
为了避免客户端和服务器端路由规则不一致,建议把路由配置抽成单独的文件,比如routes.js:
// routes.js import React from 'react'; import { Route, Switch } from 'react-router-dom'; import C1 from './C1'; import SomewherePage from './SomewherePage'; export default function Routes() { return ( <Switch> <Route exact path="/" component={C1} /> <Route path="/somewhere" component={SomewherePage} /> </Switch> ); }
然后在App.js中引入这个统一的路由组件:
// App.js import React from 'react'; import Routes from './routes'; function App() { return <Routes />; } export default App;
关于NavLink触发服务器请求的问题
你之前遇到的NavLink点击触发服务器请求,大概率是因为客户端没有用BrowserRouter正确包裹应用,导致NavLink没有被React Router的上下文管理,点击时就会走浏览器默认的跳转行为。只要按照上面的步骤配置好BrowserRouter,并且保证客户端和服务器端路由规则一致,Link或NavLink的点击都会走客户端路由,不会再向服务器发起请求。
现在你的C1组件可以正常使用Link了:
class C1 extends React.Component { render () { return (<Link to="/somewhere">somewhere</Link>); } }
内容的提问来源于stack exchange,提问作者Victor Pudeyev

