我正在使用React-router,当我点击链接按钮时,它工作得很好,但当我刷新我的网页时,它没有加载我想要的东西。
例如,我在localhost/joblist和一切都很好,因为我到达这里按下一个链接。但如果我刷新网页,我会得到:
Cannot GET /joblist
默认情况下,它不是这样工作的。最初我有我的URL localhost/#/和localhost/#/joblist,他们工作得很好。但我不喜欢这种类型的URL,所以试图删除#,我写道:
Router.run(routes, Router.HistoryLocation, function (Handler) {
React.render(<Handler/>, document.body);
});
这个问题不会发生在localhost/,这个总是返回我想要的。
这个应用程序是单页的,所以/joblist不需要向任何服务器询问任何事情。
我的整个路由器。
var routes = (
<Route name="app" path="/" handler={App}>
<Route name="joblist" path="/joblist" handler={JobList}/>
<DefaultRoute handler={Dashboard}/>
<NotFoundRoute handler={NotFound}/>
</Route>
);
Router.run(routes, Router.HistoryLocation, function (Handler) {
React.render(<Handler/>, document.body);
});
为乔舒亚·戴克的答案添加更多信息。
如果你正在使用Firebase,并且想同时使用根路由和子目录路由,你需要在你的Firebase .json中添加以下代码:
{
"hosting": {
"rewrites": [
{
"source": "*",
"destination": "/index.html"
},
{
"source": "/subdirectory/**",
"destination": "/subdirectory/index.html"
}
]
}
}
例子:
你正在为客户建立一个网站。您希望网站的所有者在https://your.domain.com/management中添加信息,而网站的用户将导航到https://your.domain.com。
在这种情况下,您的火源。Json文件是这样的:
{
"hosting": {
"rewrites": [
{
"source": "*",
"destination": "/index.html"
},
{
"source": "/management/**",
"destination": "/management/index.html"
}
]
}
}
在后端使用Express.js,在前端使用React(没有React -create-app)和reach/router,正确的reach/router路由React组件会显示出来,当在地址栏中点击Enter时,菜单链接将被设置为活动样式,例如http://localhost:8050/pages。
请签出以下内容,或直接访问我的存储库https://github.com/nickjohngray/staticbackeditor。所有的代码都在那里。
网络包:
设置代理。这允许任何从端口3000 (React)调用服务器,
包括当按下回车键时在地址栏中获取index.html或任何东西的调用。它还允许调用API路由来获取JSON数据。
比如await axios。Post ('/api/login', {email, pwd}):
devServer: {
port: 3000,
open: true,
proxy: {
'/': 'http://localhost:8050',
}
}
设置Express.js路由
app.get('*', (req, res) => {
console.log('sending index.html')
res.sendFile(path.resolve('dist', 'index.html'))
});
这将匹配React的任何请求。它只返回dist文件夹中的index.html页面。当然,这个页面有一个更单页的React应用程序。(注意任何其他路由都应该出现在这个上面,在我的情况下,这些是我的API路由。)
反应路线
<Router>
<Home path="/" />
<Pages path="pages"/>
<ErrorPage path="error"/>
<Products path="products"/>
<NotFound default />
</Router>
这些路由是在我的布局组件中定义的,当路径匹配时,该组件将加载相应的组件。
React布局构造函数
constructor(props) {
super(props);
this.props.changeURL({URL: globalHistory.location.pathname});
}
Layout构造函数在加载时立即被调用。在这里,我调用我的redux操作changeURL,我的菜单监听,所以它可以突出显示正确的菜单项,如下所示:
菜单的代码
<nav>
{this.state.links.map( (link) =>
<Link className={this.getActiveLinkClassName(link.path) } to={link.path}>
{link.name}
</Link>)}
</nav>
路由器可以用两种不同的方式调用,这取决于导航是发生在客户端还是服务器上。您已经将其配置为客户端操作。关键参数是run方法的第二个参数,即location。
当你使用React Router Link组件时,它会阻塞浏览器导航并调用transitionTo来做客户端导航。您正在使用HistoryLocation,因此它使用HTML5历史API通过在地址栏中模拟新URL来完成导航的错觉。如果您使用的是较旧的浏览器,这将不起作用。您将需要使用HashLocation组件。
When you hit refresh, you bypass all of the React and React Router code. The server gets the request for /joblist and it must return something. On the server you need to pass the path that was requested to the run method in order for it to render the correct view. You can use the same route map, but you'll probably need a different call to Router.run. As Charles points out, you can use URL rewriting to handle this. Another option is to use a Node.js server to handle all requests and pass the path value as the location argument.
例如,在Express.js中,它看起来是这样的:
var app = express();
app.get('*', function (req, res) { // This wildcard method handles all requests
Router.run(routes, req.path, function (Handler, state) {
var element = React.createElement(Handler);
var html = React.renderToString(element);
res.render('main', { content: html });
});
});
请注意,正在传递请求路径以运行。为此,需要有一个服务器端视图引擎,可以将呈现的HTML传递给该引擎。在使用renderToString和在服务器上运行React时,还有许多其他注意事项。一旦页面在服务器上呈现,当你的应用程序在客户端加载时,它将再次呈现,并根据需要更新服务器端呈现的HTML。